diff --git a/iOS/Layover/Layover.xcodeproj/project.pbxproj b/iOS/Layover/Layover.xcodeproj/project.pbxproj index fd686351..1d187ca0 100644 --- a/iOS/Layover/Layover.xcodeproj/project.pbxproj +++ b/iOS/Layover/Layover.xcodeproj/project.pbxproj @@ -151,8 +151,6 @@ 835A61A22B068115002F22A5 /* PlaybackInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835A619C2B068115002F22A5 /* PlaybackInteractor.swift */; }; 835A61A62B0B4DDD002F22A5 /* Dashboard-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 835A61A52B0B4DDD002F22A5 /* Dashboard-Regular.ttf */; }; 835A61A92B0B5A31002F22A5 /* LoginConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 835A61A82B0B5A31002F22A5 /* LoginConfigurator.swift */; }; - 8363A32D2B4C1CBB00772DDF /* PlaybackPresenterTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8363A32C2B4C1CBA00772DDF /* PlaybackPresenterTests.swift */; }; - 8363A32F2B4C329100772DDF /* PlaybackInteractorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8363A32E2B4C329100772DDF /* PlaybackInteractorTests.swift */; }; 8363A3332B4D6E9B00772DDF /* MockPlaybackWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8363A3322B4D6E9B00772DDF /* MockPlaybackWorker.swift */; }; 836C33872B15A29600ECAFB0 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836C33862B15A29600ECAFB0 /* Toast.swift */; }; 836C338B2B15D22C00ECAFB0 /* PlaybackConfigurator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836C338A2B15D22C00ECAFB0 /* PlaybackConfigurator.swift */; }; @@ -161,6 +159,7 @@ 839F1DF82B62AEDA0071C622 /* LOTextLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839F1DF72B62AEDA0071C622 /* LOTextLabel.swift */; }; 83C35E1B2B108C3500D8DD5C /* PlaybackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C35E1A2B108C3500D8DD5C /* PlaybackView.swift */; }; 83C35E1E2B10923C00D8DD5C /* PlaybackCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 83C35E1D2B10923C00D8DD5C /* PlaybackCell.swift */; }; + FC06392E2B83D3F00019E4FB /* PostsPage.json in Resources */ = {isa = PBXBuildFile; fileRef = FC06392D2B83D3F00019E4FB /* PostsPage.json */; }; FC0E80242B1A0BBB00EF56D6 /* UploadPostPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC0E801E2B1A0BBB00EF56D6 /* UploadPostPresenter.swift */; }; FC0E80252B1A0BBB00EF56D6 /* UploadPostWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC0E801F2B1A0BBB00EF56D6 /* UploadPostWorker.swift */; }; FC0E80262B1A0BBB00EF56D6 /* UploadPostRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC0E80202B1A0BBB00EF56D6 /* UploadPostRouter.swift */; }; @@ -199,6 +198,8 @@ FC4084CA2B1F291200CE4727 /* UploadVideoDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4084C92B1F291200CE4727 /* UploadVideoDTO.swift */; }; FC4084CC2B1F2F5D00CE4727 /* UploadPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC4084CB2B1F2F5D00CE4727 /* UploadPost.swift */; }; FC42E4142B17AB69005D4956 /* VideoFileWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC42E4132B17AB69005D4956 /* VideoFileWorker.swift */; }; + FC43D9DA2B6F773C00FD9BCB /* PostsPageDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC43D9D92B6F773C00FD9BCB /* PostsPageDTO.swift */; }; + FC43D9DC2B73935B00FD9BCB /* PostsPage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC43D9DB2B73935B00FD9BCB /* PostsPage.swift */; }; FC49758F2B03432800D8627F /* Pretendard-SemiBold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC4975862B03432700D8627F /* Pretendard-SemiBold.ttf */; }; FC4975932B03432800D8627F /* Pretendard-Bold.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC49758A2B03432800D8627F /* Pretendard-Bold.ttf */; }; FC4975942B03432800D8627F /* Pretendard-Regular.ttf in Resources */ = {isa = PBXBuildFile; fileRef = FC49758B2B03432800D8627F /* Pretendard-Regular.ttf */; }; @@ -245,7 +246,6 @@ FC7E45462AFEB62B004F155A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FC7E45442AFEB62B004F155A /* LaunchScreen.storyboard */; }; FC7E456A2AFEC06E004F155A /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = FC7E45692AFEC06E004F155A /* .swiftlint.yml */; }; FC8696D32B26008B00F9A7B9 /* SettingViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836C33972B1843BE00ECAFB0 /* SettingViewController.swift */; }; - FC8DC42A2B5A5B7600FC772A /* LOImageCacher in Frameworks */ = {isa = PBXBuildFile; productRef = FC8DC4292B5A5B7600FC772A /* LOImageCacher */; }; FC8DC42F2B5A5C4600FC772A /* LOImageCacher in Frameworks */ = {isa = PBXBuildFile; productRef = FC8DC42E2B5A5C4600FC772A /* LOImageCacher */; }; FC930E752B0CD75C00AA48E3 /* ProfilePresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC930E6F2B0CD75C00AA48E3 /* ProfilePresenter.swift */; }; FC930E772B0CD75C00AA48E3 /* ProfileRouter.swift in Sources */ = {isa = PBXBuildFile; fileRef = FC930E712B0CD75C00AA48E3 /* ProfileRouter.swift */; }; @@ -419,8 +419,6 @@ 835A61A52B0B4DDD002F22A5 /* Dashboard-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Dashboard-Regular.ttf"; sourceTree = ""; }; 835A61A82B0B5A31002F22A5 /* LoginConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginConfigurator.swift; sourceTree = ""; }; 835A61AA2B0B85FD002F22A5 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/LaunchScreen.strings; sourceTree = ""; }; - 8363A32C2B4C1CBA00772DDF /* PlaybackPresenterTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PlaybackPresenterTests.swift; path = LayoverTests/Mocks/Workers/PlaybackPresenterTests.swift; sourceTree = SOURCE_ROOT; }; - 8363A32E2B4C329100772DDF /* PlaybackInteractorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PlaybackInteractorTests.swift; path = LayoverTests/Mocks/Workers/PlaybackInteractorTests.swift; sourceTree = SOURCE_ROOT; }; 8363A3322B4D6E9B00772DDF /* MockPlaybackWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockPlaybackWorker.swift; sourceTree = ""; }; 836C33862B15A29600ECAFB0 /* Toast.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Toast.swift; sourceTree = ""; }; 836C338A2B15D22C00ECAFB0 /* PlaybackConfigurator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackConfigurator.swift; sourceTree = ""; }; @@ -430,6 +428,7 @@ 839F1DF72B62AEDA0071C622 /* LOTextLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LOTextLabel.swift; sourceTree = ""; }; 83C35E1A2B108C3500D8DD5C /* PlaybackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackView.swift; sourceTree = ""; }; 83C35E1D2B10923C00D8DD5C /* PlaybackCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PlaybackCell.swift; sourceTree = ""; }; + FC06392D2B83D3F00019E4FB /* PostsPage.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = PostsPage.json; sourceTree = ""; }; FC0E801E2B1A0BBB00EF56D6 /* UploadPostPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadPostPresenter.swift; sourceTree = ""; }; FC0E801F2B1A0BBB00EF56D6 /* UploadPostWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadPostWorker.swift; sourceTree = ""; }; FC0E80202B1A0BBB00EF56D6 /* UploadPostRouter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadPostRouter.swift; sourceTree = ""; }; @@ -468,6 +467,8 @@ FC4084C92B1F291200CE4727 /* UploadVideoDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadVideoDTO.swift; sourceTree = ""; }; FC4084CB2B1F2F5D00CE4727 /* UploadPost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UploadPost.swift; sourceTree = ""; }; FC42E4132B17AB69005D4956 /* VideoFileWorker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoFileWorker.swift; sourceTree = ""; }; + FC43D9D92B6F773C00FD9BCB /* PostsPageDTO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsPageDTO.swift; sourceTree = ""; }; + FC43D9DB2B73935B00FD9BCB /* PostsPage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostsPage.swift; sourceTree = ""; }; FC4975862B03432700D8627F /* Pretendard-SemiBold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-SemiBold.ttf"; sourceTree = ""; }; FC49758A2B03432800D8627F /* Pretendard-Bold.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Bold.ttf"; sourceTree = ""; }; FC49758B2B03432800D8627F /* Pretendard-Regular.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "Pretendard-Regular.ttf"; sourceTree = ""; }; @@ -642,7 +643,6 @@ 194C21C72B1DF09B00C62645 /* Scenes */ = { isa = PBXGroup; children = ( - 8363A32B2B4C1C6900772DDF /* Playback */, 19B665D32B4EEDDD0083E63C /* SignUp */, 19AE481D2B29D02700DD4612 /* EditProfile */, 19AE48122B28C2A800DD4612 /* Setting */, @@ -681,6 +681,7 @@ 194C21CE2B1DF63D00C62645 /* MockDatas */ = { isa = PBXGroup; children = ( + FC06392D2B83D3F00019E4FB /* PostsPage.json */, FC4E0C122B28609C00152596 /* PostBoard.json */, 192513972B278645001533FA /* CheckSignUp.json */, 1925138D2B278645001533FA /* CheckUserName.json */, @@ -740,6 +741,7 @@ isa = PBXGroup; children = ( 19A1692C2B17750B00DB34C0 /* Post.swift */, + FC43D9DB2B73935B00FD9BCB /* PostsPage.swift */, 19A169412B17C70C00DB34C0 /* Member.swift */, 19A169432B17C71C00DB34C0 /* Board.swift */, FC4084CB2B1F2F5D00CE4727 /* UploadPost.swift */, @@ -781,6 +783,7 @@ FC767F942B1222350088CF9B /* ProfileImageDTO.swift */, FC767F962B1224B80088CF9B /* IntroduceDTO.swift */, 19A169372B17BCA800DB34C0 /* PostDTO.swift */, + FC43D9D92B6F773C00FD9BCB /* PostsPageDTO.swift */, 19A169392B17BCC400DB34C0 /* MemberDTO.swift */, 19A1693B2B17BD1C00DB34C0 /* BoardDTO.swift */, 8321A2FE2B1E428C000A12AF /* ReportDTO.swift */, @@ -914,15 +917,6 @@ path = Playback; sourceTree = ""; }; - 8363A32B2B4C1C6900772DDF /* Playback */ = { - isa = PBXGroup; - children = ( - 8363A32C2B4C1CBA00772DDF /* PlaybackPresenterTests.swift */, - 8363A32E2B4C329100772DDF /* PlaybackInteractorTests.swift */, - ); - path = Playback; - sourceTree = ""; - }; 836C33922B18436A00ECAFB0 /* Setting */ = { isa = PBXGroup; children = ( @@ -1305,7 +1299,6 @@ name = Layover; packageProductDependencies = ( 194551FC2B0386D100299768 /* KakaoSDK */, - FC8DC4292B5A5B7600FC772A /* LOImageCacher */, 19AF2A052B5D06B9008C3620 /* HLSCachingServer */, ); productName = Layover; @@ -1419,6 +1412,7 @@ 1925139C2B278645001533FA /* DeleteVideo.json in Resources */, 1925139F2B278646001533FA /* PostListMore.json in Resources */, 1925139A2B278645001533FA /* PostList.json in Resources */, + FC06392E2B83D3F00019E4FB /* PostsPage.json in Resources */, 192513992B278645001533FA /* PostListEnd.json in Resources */, 192513A12B278646001533FA /* DeleteUser.json in Resources */, 192513A22B278646001533FA /* ReportPlaybackVideo.json in Resources */, @@ -1492,6 +1486,7 @@ 194552282B0479B600299768 /* BaseViewController.swift in Sources */, 194552212B0478B400299768 /* HomePresenter.swift in Sources */, 1972CCDA2B13A4BA00C3C762 /* SignUpWorker.swift in Sources */, + FC43D9DA2B6F773C00FD9BCB /* PostsPageDTO.swift in Sources */, 1945520D2B0399E500299768 /* MainTabBarViewController.swift in Sources */, FC2511AB2B04EA6B004717BC /* MapConfigurator.swift in Sources */, 1945523B2B05258200299768 /* HomeConfigurator.swift in Sources */, @@ -1516,6 +1511,7 @@ 194552242B0478B400299768 /* HomeModels.swift in Sources */, 8321A3012B1F1EC5000A12AF /* MockReportWorker.swift in Sources */, 19A1692D2B17750B00DB34C0 /* Post.swift in Sources */, + FC43D9DC2B73935B00FD9BCB /* PostsPage.swift in Sources */, 194552022B038B8300299768 /* OSLog+.swift in Sources */, 8321A2F92B1E15F3000A12AF /* LOReportStackView.swift in Sources */, FC0E80272B1A0BBB00EF56D6 /* UploadPostModels.swift in Sources */, @@ -1659,7 +1655,6 @@ 192513802B277CD7001533FA /* ProfileViewControllerTests.swift in Sources */, 194C21C62B1DEE6B00C62645 /* HomePresenterTests.swift in Sources */, FC4E0C202B28B4C500152596 /* MockLocationFetcher.swift in Sources */, - 8363A32D2B4C1CBB00772DDF /* PlaybackPresenterTests.swift in Sources */, 1925137A2B273D98001533FA /* StubAuthManager.swift in Sources */, 1925136D2B26F84E001533FA /* MockTagPlayListWorker.swift in Sources */, 19AE481A2B28C2B700DD4612 /* SettingPresenterTests.swift in Sources */, @@ -1667,7 +1662,6 @@ 19B665DA2B4EEDDD0083E63C /* SignUpInteractorTests.swift in Sources */, 19B665DB2B4EEDDD0083E63C /* SignUpPresenterTests.swift in Sources */, 194C21C32B1DEE6B00C62645 /* HomeViewControllerTests.swift in Sources */, - 8363A32F2B4C329100772DDF /* PlaybackInteractorTests.swift in Sources */, 192513692B26F7CE001533FA /* TagPlayListInteractorTests.swift in Sources */, 19AE48232B29D03D00DD4612 /* EditProfileInteractorTests.swift in Sources */, 194C21CC2B1DF39200C62645 /* MockHomeWorker.swift in Sources */, @@ -1991,15 +1985,15 @@ package = 194551FB2B03863B00299768 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; productName = KakaoSDK; }; - FC8DC42E2B5A5C4600FC772A /* LOImageCacher */ = { - isa = XCSwiftPackageProductDependency; - productName = LOImageCacher; - }; 19AF2A052B5D06B9008C3620 /* HLSCachingServer */ = { isa = XCSwiftPackageProductDependency; package = 19AF2A042B5D06B9008C3620 /* XCRemoteSwiftPackageReference "HLSCachingServer" */; productName = HLSCachingServer; }; + FC8DC42E2B5A5C4600FC772A /* LOImageCacher */ = { + isa = XCSwiftPackageProductDependency; + productName = LOImageCacher; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = FC7E452E2AFEB623004F155A /* Project object */; diff --git a/iOS/Layover/Layover/Models/PostsPage.swift b/iOS/Layover/Layover/Models/PostsPage.swift new file mode 100644 index 00000000..67db8b8a --- /dev/null +++ b/iOS/Layover/Layover/Models/PostsPage.swift @@ -0,0 +1,14 @@ +// +// PostsPage.swift +// Layover +// +// Created by kong on 2024/02/07. +// Copyright © 2024 CodeBomber. All rights reserved. +// + +import Foundation + +struct PostsPage { + let cursor: Int + let posts: [Post] +} diff --git a/iOS/Layover/Layover/Network/DTOs/PostsPageDTO.swift b/iOS/Layover/Layover/Network/DTOs/PostsPageDTO.swift new file mode 100644 index 00000000..444e0c61 --- /dev/null +++ b/iOS/Layover/Layover/Network/DTOs/PostsPageDTO.swift @@ -0,0 +1,33 @@ +// +// PostsPageDTO.swift +// Layover +// +// Created by kong on 2024/02/04. +// Copyright © 2024 CodeBomber. All rights reserved. +// + +import Foundation + +struct PostsPageDTO: Decodable { + let lastID: Int + let posts: [PostDTO] + + enum CodingKeys: String, CodingKey { + case lastID = "lastId" + case posts = "boardsResDto" + } +} + +struct PostRequestDTO: Encodable { + let cursor: Int? + let memberId: String? +} + +extension PostsPageDTO { + func toDomain() -> PostsPage { + return PostsPage( + cursor: lastID, + posts: posts.map { $0.toDomain() } + ) + } +} diff --git a/iOS/Layover/Layover/Network/EndPoint/Factories/PostEndPointFactory.swift b/iOS/Layover/Layover/Network/EndPoint/Factories/PostEndPointFactory.swift index 259015ce..72d588f2 100644 --- a/iOS/Layover/Layover/Network/EndPoint/Factories/PostEndPointFactory.swift +++ b/iOS/Layover/Layover/Network/EndPoint/Factories/PostEndPointFactory.swift @@ -9,17 +9,20 @@ import Foundation protocol PostEndPointFactory { - func makeHomePostListEndPoint() -> EndPoint> + func makeHomePostListEndPoint(at cursor: Int?) -> EndPoint> func makeMapPostListEndPoint(latitude: Double, longitude: Double) -> EndPoint> func makeTagSearchPostListEndPoint(of tag: String, at page: Int) -> EndPoint> } final class DefaultPostEndPointFactory: PostEndPointFactory { - func makeHomePostListEndPoint() -> EndPoint> { - return EndPoint( - path: "/board/home", - method: .GET - ) + func makeHomePostListEndPoint(at cursor: Int?) -> EndPoint> { + var queryParameters: [String: Int]? + if let cursor { + queryParameters?.updateValue(cursor, forKey: "cursor") + } + return EndPoint(path: "/board/home", + method: .GET, + queryParameters: queryParameters) } func makeMapPostListEndPoint(latitude: Double, longitude: Double) -> EndPoint> { diff --git a/iOS/Layover/Layover/Network/EndPoint/Factories/UserEndPointFactory.swift b/iOS/Layover/Layover/Network/EndPoint/Factories/UserEndPointFactory.swift index 6db1fea0..711b8107 100644 --- a/iOS/Layover/Layover/Network/EndPoint/Factories/UserEndPointFactory.swift +++ b/iOS/Layover/Layover/Network/EndPoint/Factories/UserEndPointFactory.swift @@ -14,7 +14,7 @@ protocol UserEndPointFactory { func makeIntroduceModifyEndPoint(introduce: String) -> EndPoint> func makeUserWithDrawEndPoint() -> EndPoint> func makeUserInformationEndPoint(with id: Int?) -> EndPoint> - func makeUserPostsEndPoint(at page: Int, of id: Int?) -> EndPoint> + func makeUserPostsEndPoint(at cursor: Int?, of id: Int?) -> EndPoint> func makeUserProfileImageDefaultEndPoint() -> EndPoint> func makeFetchUserProfilePresignedURL(of fileType: String) -> EndPoint> } @@ -76,12 +76,14 @@ final class DefaultUserEndPointFactory: UserEndPointFactory { ) } - func makeUserPostsEndPoint(at page: Int, of id: Int? = nil) -> EndPoint> { - var queryParameters = [String: String]() - queryParameters.updateValue(String(page), forKey: "page") - + func makeUserPostsEndPoint(at cursor: Int?, of id: Int? = nil) -> EndPoint> { + var queryParameters: PostRequestDTO? if let id { - queryParameters.updateValue(String(id), forKey: "memberId") + queryParameters = PostRequestDTO(cursor: cursor, + memberId: String(id)) + } else { + queryParameters = PostRequestDTO(cursor: cursor, + memberId: nil) } return EndPoint( diff --git a/iOS/Layover/Layover/Network/Provider/Provider.swift b/iOS/Layover/Layover/Network/Provider/Provider.swift index ce709d4c..065f2e56 100644 --- a/iOS/Layover/Layover/Network/Provider/Provider.swift +++ b/iOS/Layover/Layover/Network/Provider/Provider.swift @@ -38,10 +38,6 @@ extension ProviderType { method: method) } - func upload(from fileURL: URL, to url: String, method: HTTPMethod = .PUT) async throws -> Data { - return try await upload(from: fileURL, to: url, method: method) - } - func upload(fromFile: URL, to url: String, method: HTTPMethod = .PUT, diff --git a/iOS/Layover/Layover/Scenes/EditProfile/EditProfileViewController.swift b/iOS/Layover/Layover/Scenes/EditProfile/EditProfileViewController.swift index 328dee03..389e323a 100644 --- a/iOS/Layover/Layover/Scenes/EditProfile/EditProfileViewController.swift +++ b/iOS/Layover/Layover/Scenes/EditProfile/EditProfileViewController.swift @@ -269,8 +269,8 @@ extension EditProfileViewController: PHPickerViewControllerDelegate { } } }.resume() + picker.deselectAssets(withIdentifiers: results.compactMap(\.assetIdentifier)) } - picker.deselectAssets(withIdentifiers: results.compactMap(\.assetIdentifier)) } } } diff --git a/iOS/Layover/Layover/Scenes/Home/HomeInteractor.swift b/iOS/Layover/Layover/Scenes/Home/HomeInteractor.swift index aeddd839..73866925 100644 --- a/iOS/Layover/Layover/Scenes/Home/HomeInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Home/HomeInteractor.swift @@ -12,6 +12,8 @@ import UIKit protocol HomeBusinessLogic { @discardableResult func fetchPosts(with request: HomeModels.FetchPosts.Request) async -> Bool + @discardableResult + func fetchMorePosts() async -> Bool func playPosts(with request: HomeModels.PlayPosts.Request) func fetchLocationAuthorizationStatus() func selectVideo(with request: HomeModels.SelectVideo.Request) @@ -36,6 +38,8 @@ final class HomeInteractor: HomeDataStore { var homeWorker: HomeWorkerProtocol? var presenter: HomePresentationLogic? var locationManager: CurrentLocationManager? + var postPageLastID: Int? + var canFetchMorePosts = true // MARK: - DataStore @@ -51,14 +55,31 @@ extension HomeInteractor: HomeBusinessLogic { @discardableResult func fetchPosts(with request: Models.FetchPosts.Request) async -> Bool { - guard let posts = await homeWorker?.fetchPosts() else { return false } - let response = Models.FetchPosts.Response(posts: posts) - + guard let postsPage = await homeWorker?.fetchPosts() else { return false } + let response = Models.FetchPosts.Response(cursor: postsPage.cursor, + posts: postsPage.posts) + self.postPageLastID = response.cursor await MainActor.run { - self.posts = posts + self.posts = response.posts presenter?.presentPosts(with: response) } + return true + } + @discardableResult + func fetchMorePosts() async -> Bool { + if canFetchMorePosts { + canFetchMorePosts = false + guard let postsPage = await homeWorker?.fetchMorePosts(at: postPageLastID) else { return false } + let response = Models.FetchPosts.Response(cursor: postsPage.cursor, + posts: postsPage.posts) + self.postPageLastID = response.cursor + await MainActor.run { + self.posts = response.posts + presenter?.presentMorePosts(with: response) + } + canFetchMorePosts = true + } return true } diff --git a/iOS/Layover/Layover/Scenes/Home/HomeModels.swift b/iOS/Layover/Layover/Scenes/Home/HomeModels.swift index f607786a..ed214352 100644 --- a/iOS/Layover/Layover/Scenes/Home/HomeModels.swift +++ b/iOS/Layover/Layover/Scenes/Home/HomeModels.swift @@ -24,6 +24,7 @@ enum HomeModels { } struct Response { + let cursor: Int let posts: [Post] } diff --git a/iOS/Layover/Layover/Scenes/Home/HomePresenter.swift b/iOS/Layover/Layover/Scenes/Home/HomePresenter.swift index 59406201..69d696aa 100644 --- a/iOS/Layover/Layover/Scenes/Home/HomePresenter.swift +++ b/iOS/Layover/Layover/Scenes/Home/HomePresenter.swift @@ -10,6 +10,7 @@ import UIKit protocol HomePresentationLogic { func presentPosts(with response: HomeModels.FetchPosts.Response) + func presentMorePosts(with response: HomeModels.FetchPosts.Response) func presentPlaybackScene(with response: HomeModels.PlayPosts.Response) func presentTagPlayList(with response: HomeModels.ShowTagPlayList.Response) func presentUploadScene() @@ -43,6 +44,23 @@ final class HomePresenter: HomePresentationLogic { viewController?.displayPosts(with: viewModel) } + func presentMorePosts(with response: Models.FetchPosts.Response) { + var displayedPosts = [Models.DisplayedPost]() + + for post in response.posts { + guard let thumbnailURL = post.board.thumbnailImageURL, + let videoURL = post.board.videoURL else { continue } + let displayedPost = Models.DisplayedPost(thumbnailImageURL: thumbnailURL, + videoURL: videoURL, + title: post.board.title, + tags: post.tag) + displayedPosts.append(displayedPost) + } + + let viewModel = Models.FetchPosts.ViewModel(displayedPosts: displayedPosts) + viewController?.displayMorePosts(with: viewModel) + } + // MARK: - UseCase Present PlaybackScene func presentPlaybackScene(with response: HomeModels.PlayPosts.Response) { diff --git a/iOS/Layover/Layover/Scenes/Home/HomeViewController.swift b/iOS/Layover/Layover/Scenes/Home/HomeViewController.swift index 926cbf0c..03eef7bc 100644 --- a/iOS/Layover/Layover/Scenes/Home/HomeViewController.swift +++ b/iOS/Layover/Layover/Scenes/Home/HomeViewController.swift @@ -11,6 +11,7 @@ import UIKit protocol HomeDisplayLogic: AnyObject { func displayPosts(with viewModel: HomeModels.FetchPosts.ViewModel) + func displayMorePosts(with viewModel: HomeModels.FetchPosts.ViewModel) func routeToPlayback() func routeToTagPlayList() func routeToVideoPicker() @@ -45,6 +46,7 @@ final class HomeViewController: BaseViewController { collectionView.backgroundColor = .clear collectionView.contentInsetAdjustmentBehavior = .always collectionView.alwaysBounceVertical = false + collectionView.alwaysBounceHorizontal = true return collectionView }() @@ -139,6 +141,7 @@ final class HomeViewController: BaseViewController { section.interGroupSpacing = 13 section.contentInsets = NSDirectionalEdgeInsets(top: 0, leading: 30, bottom: 0, trailing: 30) section.orthogonalScrollingBehavior = .groupPagingCentered + if #available(iOS 17.0, *) { section.orthogonalScrollingProperties.decelerationRate = .normal section.orthogonalScrollingProperties.bounce = .never @@ -148,12 +151,19 @@ final class HomeViewController: BaseViewController { let containerWidth = environment.container.contentSize.width items.forEach { item in + let itemCount = self.carouselDatasource.snapshot().itemIdentifiers.count + let isLastItem = itemCount - 1 == item.indexPath.row let itemCenterRelativeToOffset = item.frame.midX - offset.x // 아이템 중심점과 container offset(왼쪽)의 거리 let distanceFromCenter = abs(itemCenterRelativeToOffset - containerWidth / 2.0) // container 중심점과 아이템 중심점의 거리 let scale = max(maximumZoomScale - (distanceFromCenter / containerWidth), minimumZoomScale) // 최대 비율에서 거리에 따라 비율을 줄임, 최소 비율보다 작아지지 않도록 함 item.transform = CGAffineTransform(scaleX: 1.0, y: scale) guard let cell = self.carouselCollectionView.cellForItem(at: item.indexPath) as? HomeCarouselCollectionViewCell else { return } if scale >= 0.9 { + if isLastItem && itemCenterRelativeToOffset - containerWidth / 2.0 < 0 { + Task { + await self.interactor?.fetchMorePosts() + } + } cell.playVideo() } else if scale < 0.9 { cell.pauseVideo() @@ -245,6 +255,12 @@ extension HomeViewController: HomeDisplayLogic { } } + func displayMorePosts(with viewModel: HomeModels.FetchPosts.ViewModel) { + var snapshot = carouselDatasource.snapshot() + snapshot.appendItems(viewModel.displayedPosts) + carouselDatasource.apply(snapshot) + } + func routeToPlayback() { router?.routeToPlayback() } diff --git a/iOS/Layover/Layover/Scenes/Home/HomeWorker.swift b/iOS/Layover/Layover/Scenes/Home/HomeWorker.swift index a3f749cd..6612d232 100644 --- a/iOS/Layover/Layover/Scenes/Home/HomeWorker.swift +++ b/iOS/Layover/Layover/Scenes/Home/HomeWorker.swift @@ -10,7 +10,8 @@ import UIKit import OSLog protocol HomeWorkerProtocol { - func fetchPosts() async -> [Post]? + func fetchPosts() async -> PostsPage? + func fetchMorePosts(at cursor: Int?) async -> PostsPage? } final class HomeWorker: HomeWorkerProtocol { @@ -30,18 +31,29 @@ final class HomeWorker: HomeWorkerProtocol { // MARK: - Methods - func fetchPosts() async -> [Post]? { - let endPoint = postEndPointFactory.makeHomePostListEndPoint() + func fetchPosts() async -> PostsPage? { + let endPoint = postEndPointFactory.makeHomePostListEndPoint(at: nil) do { let response = try await provider.request(with: endPoint) - guard let posts = response.data else { return nil } - return await fetchThumbnailImageData(of: posts) + guard let postsPage = response.data else { return nil } + return postsPage.toDomain() } catch { os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) return nil } } + func fetchMorePosts(at cursor: Int?) async -> PostsPage? { + let endPoint = postEndPointFactory.makeHomePostListEndPoint(at: cursor) + do { + let response = try await provider.request(with: endPoint) + guard let postsPage = response.data else { return nil } + return postsPage.toDomain() + } catch { + return nil + } + } + private func fetchThumbnailImageData(of posts: [PostDTO]) async -> [Post] { await withTaskGroup(of: Post.self, returning: [Post].self) { group in for post in posts { diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift index 2d759fa6..6305fa19 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackInteractor.swift @@ -77,6 +77,8 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { private var isFetchReqeust: Bool = false + private var postsPageCursor: Int? + private var currentPage: Int = 1 var playbackVideoInfos: [Models.PlaybackInfo] = [] @@ -369,7 +371,9 @@ final class PlaybackInteractor: PlaybackBusinessLogic, PlaybackDataStore { var newPosts: [Post]? switch parentView { case .home: - newPosts = await worker?.fetchHomePosts() + let postsPage = await worker?.fetchHomePosts(at: postsPageCursor) + newPosts = postsPage?.posts + postsPageCursor = postsPage?.cursor case .map: return case .myProfile, .otherProfile: diff --git a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift index fabf7c2d..00e55c80 100644 --- a/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift +++ b/iOS/Layover/Layover/Scenes/Playback/PlaybackWorker.swift @@ -16,7 +16,7 @@ protocol PlaybackWorkerProtocol { func makeInfiniteScroll(posts: [Post]) -> [Post] func transLocation(latitude: Double, longitude: Double) async -> String? func fetchImageData(with url: URL?) async -> Data? - func fetchHomePosts() async -> [Post]? + func fetchHomePosts(at cursor: Int?) async -> PostsPage? func fetchProfilePosts(profileID: Int?, page: Int) async -> [Post]? func fetchTagPosts(selectedTag: String, page: Int) async -> [Post]? func isMyVideo(currentCellMemberID: Int) -> Bool @@ -102,11 +102,11 @@ final class PlaybackWorker: PlaybackWorkerProtocol { } } - func fetchHomePosts() async -> [Post]? { - let endPoint = defaultPostEndPointFactory.makeHomePostListEndPoint() + func fetchHomePosts(at cursor: Int? = nil) async -> PostsPage? { + let endPoint = defaultPostEndPointFactory.makeHomePostListEndPoint(at: cursor) do { let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.toDomain() } catch { os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) return nil @@ -117,7 +117,7 @@ final class PlaybackWorker: PlaybackWorkerProtocol { let endPoint = defaultUserEndPointFactory.makeUserPostsEndPoint(at: page, of: profileID) do { let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.posts.map { $0.toDomain() } } catch { os_log(.error, log: .data, "Failed to fetch posts: %@", error.localizedDescription) return nil diff --git a/iOS/Layover/Layover/Scenes/Profile/ProfileInteractor.swift b/iOS/Layover/Layover/Scenes/Profile/ProfileInteractor.swift index 0b1b606c..56c5e073 100644 --- a/iOS/Layover/Layover/Scenes/Profile/ProfileInteractor.swift +++ b/iOS/Layover/Layover/Scenes/Profile/ProfileInteractor.swift @@ -35,7 +35,7 @@ final class ProfileInteractor: ProfileBusinessLogic, ProfileDataStore { var presenter: ProfilePresentationLogic? var userWorker: UserWorkerProtocol? - private var fetchPostsPage = 1 + private var postsPageCursor: Int? private var canFetchMorePosts = true private var isMyProfile: Bool { profileId == nil @@ -55,7 +55,6 @@ final class ProfileInteractor: ProfileBusinessLogic, ProfileDataStore { @discardableResult func fetchProfile(with request: ProfileModels.FetchProfile.Request) async -> Bool { - fetchPostsPage = 1 canFetchMorePosts = true posts = [] guard let userProfile = await userWorker?.fetchProfile(by: profileId) else { @@ -66,16 +65,10 @@ final class ProfileInteractor: ProfileBusinessLogic, ProfileDataStore { let posts = await fetchPosts() canFetchMorePosts = !posts.isEmpty - fetchPostsPage += 1 - var imageData: Data? = nil - if let profileImageURL = userProfile.profileImageURL { - imageData = await userWorker?.fetchImageData(with: profileImageURL) - } - profileImageData = imageData let response = Models.FetchProfile.Response(userProfile: ProfileModels.Profile(username: userProfile.username, introduce: userProfile.introduce, - profileImageData: imageData), + profileImageURL: userProfile.profileImageURL), displayedPosts: posts) await MainActor.run { presenter?.presentProfile(with: response) @@ -86,43 +79,33 @@ final class ProfileInteractor: ProfileBusinessLogic, ProfileDataStore { @discardableResult func fetchMorePosts(with request: ProfileModels.FetchMorePosts.Request) async -> Bool { guard canFetchMorePosts else { return false } - let fetchedPosts = await fetchPosts() - fetchPostsPage += 1 - + let fetchedPosts = await fetchPosts(at: postsPageCursor) if fetchedPosts.isEmpty { canFetchMorePosts = false return false } - let response = Models.FetchMorePosts.Response(displayedPosts: fetchedPosts) await MainActor.run { presenter?.presentMorePosts(with: response) } - return true } - private func fetchPosts() async -> [Models.DisplayedPost] { - guard let fetchedPosts = await userWorker?.fetchPosts(at: fetchPostsPage, of: profileId), - fetchedPosts.count > 0 else { + private func fetchPosts(at cursor: Int? = nil) async -> [Models.DisplayedPost] { + guard let fetchedPostsPage = await userWorker?.fetchPosts(at: cursor, of: profileId), + fetchedPostsPage.posts.count > 0 else { return [] } + let fetchedPosts = fetchedPostsPage.posts posts += fetchedPosts + postsPageCursor = fetchedPostsPage.cursor - var responsePosts = [Models.DisplayedPost]() - for post in fetchedPosts { - if !isMyProfile && post.board.status != .complete { continue } - guard let thumbnailURL = post.board.thumbnailImageURL, - let profileImageData = await userWorker?.fetchImageData(with: thumbnailURL) else { - responsePosts.append(.init(id: post.board.identifier, thumbnailImageData: nil, status: post.board.status)) - continue - } - - responsePosts.append(Models.DisplayedPost(id: post.board.identifier, thumbnailImageData: profileImageData, status: post.board.status)) + return fetchedPosts.map { post in + Models.DisplayedPost(id: post.board.identifier, + thumbnailImageData: post.board.thumbnailImageURL, + status: post.board.status) } - - return responsePosts } func showPostDetail(with request: ProfileModels.ShowPostDetail.Request) { diff --git a/iOS/Layover/Layover/Scenes/Profile/ProfileModels.swift b/iOS/Layover/Layover/Scenes/Profile/ProfileModels.swift index 55aec64a..d9463630 100644 --- a/iOS/Layover/Layover/Scenes/Profile/ProfileModels.swift +++ b/iOS/Layover/Layover/Scenes/Profile/ProfileModels.swift @@ -13,12 +13,12 @@ enum ProfileModels { struct Profile: Hashable { let username: String let introduce: String? - let profileImageData: Data? + let profileImageURL: URL? } struct DisplayedPost: Hashable { let id: Int - let thumbnailImageData: Data? + let thumbnailImageData: URL? let status: BoardStatus } diff --git a/iOS/Layover/Layover/Scenes/Profile/ProfileViewController.swift b/iOS/Layover/Layover/Scenes/Profile/ProfileViewController.swift index 8bafdd1b..ea3c4ebc 100644 --- a/iOS/Layover/Layover/Scenes/Profile/ProfileViewController.swift +++ b/iOS/Layover/Layover/Scenes/Profile/ProfileViewController.swift @@ -7,6 +7,7 @@ // import UIKit +import LOImageCacher protocol ProfileDisplayLogic: AnyObject { func displayProfile(viewModel: ProfileModels.FetchProfile.ViewModel) @@ -153,14 +154,7 @@ final class ProfileViewController: BaseViewController { private func setDataSource() { let profileCellRegistration = UICollectionView.CellRegistration { [weak self] cell, _, itemIdentifier in guard let self else { return } - - var profileImage = UIImage.profile - if let profileImageData = itemIdentifier.profileImageData, - let image = UIImage(data: profileImageData) { - profileImage = image - } - - cell.configure(profileImage: profileImage, + cell.configure(profileImageURL: itemIdentifier.profileImageURL, nickname: itemIdentifier.username, introduce: itemIdentifier.introduce) switch profileType { @@ -174,13 +168,7 @@ final class ProfileViewController: BaseViewController { } let postCellRegistration = UICollectionView.CellRegistration { cell, indexPath, itemIdentifier in - - if let imageData = itemIdentifier.thumbnailImageData, - let image = UIImage(data: imageData) { - cell.configure(image: image, status: itemIdentifier.status) - } else { - cell.configure(image: nil, status: itemIdentifier.status) - } + cell.configure(image: itemIdentifier.thumbnailImageData, status: itemIdentifier.status) } collectionViewDatasource = UICollectionViewDiffableDataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in @@ -261,7 +249,6 @@ extension ProfileViewController: UICollectionViewDelegate { let contentHeight = scrollView.contentSize.height let scrollOffset = scrollView.contentOffset.y let height = scrollView.bounds.height - if scrollOffset > 0 && scrollOffset > contentHeight - height { fetchPosts() } diff --git a/iOS/Layover/Layover/Scenes/Profile/Views/ProfileCollectionViewCell.swift b/iOS/Layover/Layover/Scenes/Profile/Views/ProfileCollectionViewCell.swift index 0bd7731d..7e2c65e7 100644 --- a/iOS/Layover/Layover/Scenes/Profile/Views/ProfileCollectionViewCell.swift +++ b/iOS/Layover/Layover/Scenes/Profile/Views/ProfileCollectionViewCell.swift @@ -54,10 +54,14 @@ final class ProfileCollectionViewCell: UICollectionViewCell { // MARK: - Methods - func configure(profileImage: UIImage?, + func configure(profileImageURL: URL?, nickname: String?, introduce: String?) { - profileImageView.image = profileImage + if let profileImageURL { + profileImageView.lo.setImage(with: profileImageURL) + } else { + profileImageView.image = UIImage.profile + } nicknameLabel.text = nickname introduceLabel.text = introduce } diff --git a/iOS/Layover/Layover/Scenes/Profile/Views/ThumbnailCollectionViewCell.swift b/iOS/Layover/Layover/Scenes/Profile/Views/ThumbnailCollectionViewCell.swift index d343b588..6a9371f6 100644 --- a/iOS/Layover/Layover/Scenes/Profile/Views/ThumbnailCollectionViewCell.swift +++ b/iOS/Layover/Layover/Scenes/Profile/Views/ThumbnailCollectionViewCell.swift @@ -43,8 +43,11 @@ final class ThumbnailCollectionViewCell: UICollectionViewCell { // MARK: - Methods - func configure(image: UIImage?, status: BoardStatus) { - thumbnailImageView.image = image + func configure(image: URL?, status: BoardStatus) { + + if let image { + thumbnailImageView.lo.setImage(with: image) + } switch status { case .complete: diff --git a/iOS/Layover/Layover/Scenes/Report/ReportModels.swift b/iOS/Layover/Layover/Scenes/Report/ReportModels.swift index f7cd3d66..8411cb14 100644 --- a/iOS/Layover/Layover/Scenes/Report/ReportModels.swift +++ b/iOS/Layover/Layover/Scenes/Report/ReportModels.swift @@ -20,7 +20,7 @@ enum ReportModels { var description: String { switch self { case .success: - "신고가 접수되었습니다." + "신고가 접수되었습니다.\n해당 컨텐츠는 검토 후, 24시간 내에 차단 처리됩니다." case .fail: "신고 접수에 실패했습니다. 다시 시도해주세요." } diff --git a/iOS/Layover/Layover/Workers/Mocks/MockHomeWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockHomeWorker.swift index cd6570fa..a3d13c4b 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockHomeWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockHomeWorker.swift @@ -18,7 +18,7 @@ final class MockHomeWorker: HomeWorkerProtocol { // MARK: - Methods - func fetchPosts() async -> [Post]? { + func fetchPosts() async -> PostsPage? { guard let fileLocation = Bundle.main.url(forResource: "PostList", withExtension: "json") else { return nil } @@ -31,17 +31,21 @@ final class MockHomeWorker: HomeWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint: EndPoint = EndPoint>(path: "/board/home", + let endPoint: EndPoint = EndPoint>(path: "/board/home", method: .GET) let response = try await provider.request(with: endPoint) guard let data = response.data else { return nil } - return data.map { $0.toDomain() } + return data.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil } } + func fetchMorePosts(at cursor: Int?) async -> PostsPage? { + return nil + } + func fetchImageData(of url: URL) async -> Data? { do { guard let imageURL = Bundle.main.url(forResource: "sample", withExtension: "jpeg") else { diff --git a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift index a0fd828d..21c81487 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockPlaybackWorker.swift @@ -20,7 +20,7 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { private let authManager: AuthManagerProtocol // MARK: - Methods - + init(provider: ProviderType = Provider(session: .initMockSession()), authManager: AuthManagerProtocol = StubAuthManager()) { self.provider = provider self.authManager = authManager @@ -108,7 +108,7 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { } } - func fetchHomePosts() async -> [Post]? { + func fetchHomePosts(at cursor: Int?) async -> PostsPage? { guard let fileLocation = Bundle.main.url(forResource: "PostList", withExtension: "json") else { return nil } @@ -121,11 +121,11 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint: EndPoint = EndPoint>(path: "/board/home", + let endPoint: EndPoint = EndPoint>(path: "/board/home", method: .GET) let response = try await provider.request(with: endPoint) guard let data = response.data else { return nil } - return data.map { $0.toDomain() } + return data.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil diff --git a/iOS/Layover/Layover/Workers/Mocks/MockUserWorker.swift b/iOS/Layover/Layover/Workers/Mocks/MockUserWorker.swift index 4bc0a52a..f805e8d7 100644 --- a/iOS/Layover/Layover/Workers/Mocks/MockUserWorker.swift +++ b/iOS/Layover/Layover/Workers/Mocks/MockUserWorker.swift @@ -10,6 +10,7 @@ import Foundation import OSLog final class MockUserWorker: UserWorkerProtocol { + // MARK: - Properties @@ -149,9 +150,11 @@ final class MockUserWorker: UserWorkerProtocol { } } - func fetchPosts(at page: Int, of id: Int?) async -> [Post]? { - let resourceFileName = switch page { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } - guard let fileLocation = Bundle.main.url(forResource: resourceFileName, withExtension: "json") else { return nil } + func fetchPosts(at cursor: Int?, of id: Int?) async -> PostsPage? { +// let resourceFileName = switch page { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } +// let resourceFileName = cursor != nil ? "PostsPage" : "PostList" + + guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostsPage", withExtension: "json") else { return nil } do { let mockData = try Data(contentsOf: fileLocation) MockURLProtocol.requestHandler = { request in @@ -161,16 +164,40 @@ final class MockUserWorker: UserWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint = EndPoint>(path: "/member/posts", + let endPoint = EndPoint>(path: "/member/posts", method: .GET, - queryParameters: ["page": page]) + queryParameters: PostRequestDTO(cursor: cursor, + memberId: "\(id)")) let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil } } +// +// func fetchPosts(at cursor: Int?, of id: Int?) async -> PostsPage? { +// let resourceFileName = switch cursor { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } +// guard let fileLocation = Bundle.main.url(forResource: resourceFileName, withExtension: "json") else { return nil } +// do { +// let mockData = try Data(contentsOf: fileLocation) +// MockURLProtocol.requestHandler = { request in +// let response = HTTPURLResponse(url: request.url!, +// statusCode: 200, +// httpVersion: nil, +// headerFields: nil) +// return (response, mockData, nil) +// } +// let endPoint = EndPoint>(path: "/member/posts", +// method: .GET, +// queryParameters: ["cursor": cursor]) +// let response = try await provider.request(with: endPoint) +// return response.data?.toDomain() +// } catch { +// os_log(.error, log: .data, "%@", error.localizedDescription) +// return nil +// } +// } func fetchImageData(with url: URL) async -> Data? { do { diff --git a/iOS/Layover/Layover/Workers/UserWorker.swift b/iOS/Layover/Layover/Workers/UserWorker.swift index 6186f05c..b2ab632b 100644 --- a/iOS/Layover/Layover/Workers/UserWorker.swift +++ b/iOS/Layover/Layover/Workers/UserWorker.swift @@ -36,7 +36,7 @@ protocol UserWorkerProtocol { func logout() func fetchProfile(by id: Int?) async -> Member? - func fetchPosts(at page: Int, of id: Int?) async -> [Post]? + func fetchPosts(at cursor: Int?, of id: Int?) async -> PostsPage? func fetchImageData(with url: URL) async -> Data? func setProfileImageDefault() async -> Bool func fetchImagePresignedURL(with fileType: String) async -> String? @@ -153,12 +153,12 @@ class UserWorker: UserWorkerProtocol { } } - func fetchPosts(at page: Int, of id: Int?) async -> [Post]? { - let endPoint = userEndPointFactory.makeUserPostsEndPoint(at: page, of: id) + func fetchPosts(at cursor: Int?, of id: Int?) async -> PostsPage? { + let endPoint = userEndPointFactory.makeUserPostsEndPoint(at: cursor, of: id) do { let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.toDomain() } catch { os_log(.error, log: .data, "Error: %s", error.localizedDescription) return nil @@ -178,7 +178,7 @@ class UserWorker: UserWorkerProtocol { let endPoint = userEndPointFactory.makeUserProfileImageDefaultEndPoint() do { - let _ = try await provider.request(with: endPoint) + _ = try await provider.request(with: endPoint) return true } catch { os_log(.error, log: .data, "Error: %s", error.localizedDescription) diff --git a/iOS/Layover/LayoverTests/Mocks/MockDatas/PostsPage.json b/iOS/Layover/LayoverTests/Mocks/MockDatas/PostsPage.json new file mode 100644 index 00000000..5a0e28f9 --- /dev/null +++ b/iOS/Layover/LayoverTests/Mocks/MockDatas/PostsPage.json @@ -0,0 +1,32 @@ +{ + "customCode": "SUCCESS", + "message": "성공", + "statusCode": 200, + "data": { + "lastId": 32, + "boardsResDto": [ + { + "member": { + "id": 221, + "username": "hwani", + "introduce": "Hi, my name is hwani", + "profile_image_url": "https://layover-profile-image.kr.obj..." + }, + "board": { + "id": 1, + "encoded_video_url": "https://qc66zhsq1708.edge.naverncp.com/hls/fMG98Ec1UirV-awtm4qKJyhanmRFlPLZbTs_/layover-station/sv_AVC_HD, SD_1Pass_30fps.mp4/index.m3u8", + "video_thumbnail_url": "https://layover-video-thumbnail.kr.obj...", + "latitude": 37.0532156213, + "longitude": 37.0532156213, + "title": "붓산 광안리", + "content": "날씨가 정말 좋았따이", + "status": "COMPLETE" + }, + "tag": [ + "tag1", + "tag2" + ] + } + ] + } +} diff --git a/iOS/Layover/LayoverTests/Mocks/Workers/MockHomeWorker.swift b/iOS/Layover/LayoverTests/Mocks/Workers/MockHomeWorker.swift index 09f13b56..2bc796d1 100644 --- a/iOS/Layover/LayoverTests/Mocks/Workers/MockHomeWorker.swift +++ b/iOS/Layover/LayoverTests/Mocks/Workers/MockHomeWorker.swift @@ -19,8 +19,8 @@ final class MockHomeWorker: HomeWorkerProtocol { // MARK: - Methods - func fetchPosts() async -> [Post]? { - guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostList", + func fetchPosts() async -> PostsPage? { + guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostsPage", withExtension: "json"), let imageDataLocation = Bundle(for: type(of: self)).url(forResource: "sample", withExtension: "jpeg") @@ -35,18 +35,38 @@ final class MockHomeWorker: HomeWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint: EndPoint = EndPoint>(path: "/board/home", + let endPoint: EndPoint = EndPoint>(path: "/board/home", method: .GET) let response = try await provider.request(with: endPoint) - guard let responseData = response.data else { return nil } + guard let data = response.data else { return nil } + return data.toDomain() + } catch { + os_log(.error, log: .data, "%@", error.localizedDescription) + return nil + } + } - let data = responseData.map { - var domainData = $0.toDomain() - domainData.thumbnailImageData = try? Data(contentsOf: imageDataLocation) - return domainData - } + func fetchMorePosts(at cursor: Int?) async -> PostsPage? { + guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostsPage", + withExtension: "json"), + let imageDataLocation = Bundle(for: type(of: self)).url(forResource: "sample", + withExtension: "jpeg") + else { return nil } - return data + do { + let mockData = try Data(contentsOf: fileLocation) + MockURLProtocol.requestHandler = { request in + let response = HTTPURLResponse(url: request.url!, + statusCode: 200, + httpVersion: nil, + headerFields: nil) + return (response, mockData, nil) + } + let endPoint: EndPoint = EndPoint>(path: "/board/home", + method: .GET) + let response = try await provider.request(with: endPoint) + guard let data = response.data else { return nil } + return data.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil diff --git a/iOS/Layover/LayoverTests/Mocks/Workers/MockPlaybackWorker.swift b/iOS/Layover/LayoverTests/Mocks/Workers/MockPlaybackWorker.swift index dc62d72e..3dc33b80 100644 --- a/iOS/Layover/LayoverTests/Mocks/Workers/MockPlaybackWorker.swift +++ b/iOS/Layover/LayoverTests/Mocks/Workers/MockPlaybackWorker.swift @@ -94,7 +94,7 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { } } - func fetchHomePosts() async -> [Post]? { + func fetchHomePosts(at cursor: Int?) async -> PostsPage? { guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostList", withExtension: "json") else { return nil } do { let mockData = try Data(contentsOf: fileLocation) @@ -105,11 +105,11 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint: EndPoint = EndPoint>(path: "/board/home", + let endPoint: EndPoint = EndPoint>(path: "/board/home", method: .GET) let response = try await provider.request(with: endPoint) guard let data = response.data else { return nil } - return data.map { $0.toDomain() } + return data.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil @@ -128,11 +128,11 @@ final class MockPlaybackWorker: PlaybackWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint = EndPoint>(path: "/member/posts", + let endPoint = EndPoint>(path: "/member/posts", method: .GET, queryParameters: ["page": page]) let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.posts.map { $0.toDomain() } } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil diff --git a/iOS/Layover/LayoverTests/Mocks/Workers/MockUserWorker.swift b/iOS/Layover/LayoverTests/Mocks/Workers/MockUserWorker.swift index 5faa754d..72a322e8 100644 --- a/iOS/Layover/LayoverTests/Mocks/Workers/MockUserWorker.swift +++ b/iOS/Layover/LayoverTests/Mocks/Workers/MockUserWorker.swift @@ -149,9 +149,8 @@ class MockUserWorker: UserWorkerProtocol { } } - func fetchPosts(at page: Int, of id: Int?) async -> [Post]? { - let resourceFileName = switch page { case 1: "PostList" case 2: "PostListMore" default: "PostListEnd" } - guard let fileLocation = Bundle(for: type(of: self)).url(forResource: resourceFileName, withExtension: "json") else { return nil } + func fetchPosts(at cursor: Int?, of id: Int?) async -> PostsPage? { + guard let fileLocation = Bundle(for: type(of: self)).url(forResource: "PostsPage", withExtension: "json") else { return nil } do { let mockData = try Data(contentsOf: fileLocation) MockURLProtocol.requestHandler = { request in @@ -161,11 +160,12 @@ class MockUserWorker: UserWorkerProtocol { headerFields: nil) return (response, mockData, nil) } - let endPoint = EndPoint>(path: "/member/posts", + let endPoint = EndPoint>(path: "/member/posts", method: .GET, - queryParameters: ["page": page]) + queryParameters: PostRequestDTO(cursor: cursor, + memberId: "\(id)")) let response = try await provider.request(with: endPoint) - return response.data?.map { $0.toDomain() } + return response.data?.toDomain() } catch { os_log(.error, log: .data, "%@", error.localizedDescription) return nil @@ -205,4 +205,6 @@ class MockUserWorker: UserWorkerProtocol { func fetchImagePresignedURL(with fileType: String) async -> String? { return "https://s3.ap-northeast-2.amazonaws.com/sofastcar/member/1/profile.jpeg" } + + } diff --git a/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackInteractorTests.swift b/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackInteractorTests.swift deleted file mode 100644 index 9e60b17b..00000000 --- a/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackInteractorTests.swift +++ /dev/null @@ -1,824 +0,0 @@ -// -// PlaybackInteractorTests.swift -// LayoverTests -// -// Created by 황지웅 on 12/12/23. -// Copyright © 2023 CodeBomber. All rights reserved. -// - -@testable import Layover -import XCTest - -final class PlaybackInteractorTests: XCTestCase { - // MARK: Subject under test - - var sut: PlaybackInteractor! - - // MARK: Properties - - typealias Models = PlaybackModels - - // MARK: - Test lifecycle - - override func setUp() { - super.setUp() - setupPlaybackInteracotr() - } - - override func tearDown() { - super.tearDown() - } - - // MARK: - Test setup - - func setupPlaybackInteracotr() { - sut = PlaybackInteractor() - sut.worker = MockPlaybackWorker() - } - - // MARK: - Test doubles - - final class PlaybackPresentationLogicSpy: PlaybackPresentationLogic { - var presentVideoListDidCalled = false - var presentVideoListResponse: Models.LoadPlaybackVideoList.Response! - - var presentLoadFetchVideosDidCalled = false - var presentLoadFetchVideosResponse: Models.LoadPlaybackVideoList.Response! - - var presentSetInitialPlaybackCellDidCalled = false - var presentSetInitialPlaybackCellResponse: Models.SetInitialPlaybackCell.Response! - - var presentMoveInitialPlaybackCellDidCalled = false - var presentMoveInitialPlaybackCellResponse: Models.SetInitialPlaybackCell.Response! - - var presentMoveCellNextDidCalled = false - var presentMoveCellNextResponse: Models.DisplayPlaybackVideo.Response! - - var presentPlayInitialPlaybackCellDidCalled = false - var presentPlayInitialPlaybackCellResponse: Models.DisplayPlaybackVideo.Response! - - var presentShowPlayerSliderDidCalled = false - var presentShowPlayerSliderResponse: Models.DisplayPlaybackVideo.Response! - - var presentTeleportCellDidCalled = false - var presentTeleportCellResponse: Models.DisplayPlaybackVideo.Response! - - var presentLeavePlaybackViewDidCalled = false - var presentLeavePlaybackViewResponse: Models.DisplayPlaybackVideo.Response! - - var presentResetPlaybackCellDidCalled = false - var presentResetPlaybackCellResponse: Models.DisplayPlaybackVideo.Response! - - var presentConfigureCellDidCalled = false - var presentConfigureCellResponse: Models.ConfigurePlaybackCell.Response! - - var presentSetSeemoreButtonDidCalled = false - var presentSetSeemoreButtonResponse: Models.SetSeemoreButton.Response! - - var presentDeleteVideoDidCalled = false - var presentDeleteVideoResponse: Models.DeletePlaybackVideo.Response! - - var presentProfileDidCalled = false - - var presentTagPlayDidCalled = false - - var presentLoadProfileImageAndLocationDidCalled = false - var presentLoadProfileImageAndLocationResponse: Models.LoadProfileImageAndLocation.Response! - - var presentSeekVideoDidCalled = false - var presentSeekVideoResponse: Models.SeekVideo.Response! - - var presentReportVideoDidCalled = false - - func presentVideoList(with response: Layover.PlaybackModels.LoadPlaybackVideoList.Response) { - presentVideoListDidCalled = true - presentVideoListResponse = response - } - - func presentLoadFetchVideos(with response: Layover.PlaybackModels.LoadPlaybackVideoList.Response) { - presentLoadFetchVideosDidCalled = true - presentLoadFetchVideosResponse = response - } - - func presentSetInitialPlaybackCell(with response: Layover.PlaybackModels.SetInitialPlaybackCell.Response) { - presentSetInitialPlaybackCellDidCalled = true - presentSetInitialPlaybackCellResponse = response - } - - func presentMoveInitialPlaybackCell(with response: Layover.PlaybackModels.SetInitialPlaybackCell.Response) { - presentMoveInitialPlaybackCellDidCalled = true - presentMoveInitialPlaybackCellResponse = response - } - - func presentMoveCellNext(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentMoveCellNextDidCalled = true - presentMoveCellNextResponse = response - } - - func presentPlayInitialPlaybackCell(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentPlayInitialPlaybackCellDidCalled = true - presentPlayInitialPlaybackCellResponse = response - } - - func presentShowPlayerSlider(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentShowPlayerSliderDidCalled = true - presentShowPlayerSliderResponse = response - } - - func presentTeleportCell(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentTeleportCellDidCalled = true - presentTeleportCellResponse = response - } - - func presentLeavePlaybackView(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentLeavePlaybackViewDidCalled = true - presentLeavePlaybackViewResponse = response - } - - func presentResetPlaybackCell(with response: Layover.PlaybackModels.DisplayPlaybackVideo.Response) { - presentResetPlaybackCellDidCalled = true - presentResetPlaybackCellResponse = response - } - - func presentConfigureCell(with response: Layover.PlaybackModels.ConfigurePlaybackCell.Response) { - presentConfigureCellDidCalled = true - presentConfigureCellResponse = response - } - - func presentSetSeemoreButton(with response: Layover.PlaybackModels.SetSeemoreButton.Response) { - presentSetSeemoreButtonDidCalled = true - presentSetSeemoreButtonResponse = response - } - - func presentDeleteVideo(with response: Layover.PlaybackModels.DeletePlaybackVideo.Response) { - presentDeleteVideoDidCalled = true - presentDeleteVideoResponse = response - } - - func presentProfile() { - presentProfileDidCalled = true - } - - func presentTagPlay() { - presentTagPlayDidCalled = true - } - - func presentLoadProfileImageAndLocation(with response: Layover.PlaybackModels.LoadProfileImageAndLocation.Response) { - presentLoadProfileImageAndLocationDidCalled = true - presentLoadProfileImageAndLocationResponse = response - } - - func presentSeekVideo(with response: Layover.PlaybackModels.SeekVideo.Response) { - presentSeekVideoDidCalled = true - presentSeekVideoResponse = response - } - - func presentReportVideo() { - presentReportVideoDidCalled = true - } - } - - // MARK: - Tests - - func test_parentView가_map일_때_displayVideoList를_호출하면_presentVideoList를_호출하고_올바른_데이터를_전달한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.presenter = spy - sut.parentView = .map - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.videoURLNilPost] - - Task { - // Act - await sut.displayVideoList() - - // Assert - XCTAssertTrue(spy.presentVideoListDidCalled, "displayVideoList는 presentVideoList를 호출하지 않았습니다") - // map이므로 2 + 더미셀 2 = 4 - // videoURL이 nil이면 거름 - XCTAssertEqual(spy.presentVideoListResponse.videos.count, 4) - XCTAssertEqual(spy.presentVideoListResponse.videos[0].displayedPost, spy.presentVideoListResponse.videos[2].displayedPost) - XCTAssertEqual(spy.presentVideoListResponse.videos[1].displayedPost, spy.presentVideoListResponse.videos[1].displayedPost) - XCTAssertEqual(spy.presentVideoListResponse.videos.first!.displayedPost, Seeds.PlaybackVideos.videos.last!.displayedPost) - XCTAssertEqual(spy.presentVideoListResponse.videos.last!.displayedPost, Seeds.PlaybackVideos.videos.first!.displayedPost) - } - } - - func test_displayVideoList를_호출하면_presentVideoList를_호출하고_올바른_데이터를_전달한다_parentView가_map이_아닐때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.presenter = spy - sut.parentView = .home - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.videoURLNilPost] - - Task { - // Act - await sut.displayVideoList() - - // Assert - XCTAssertTrue(spy.presentVideoListDidCalled, "displayVideoList는 presentVideoList를 호출하지 않았습니다") - // map이므로 2 + 더미셀 2 = 4 - // videoURL이 nil이면 거름 - XCTAssertEqual(spy.presentVideoListResponse.videos.count, 2) - XCTAssertEqual(spy.presentVideoListResponse.videos.first!.displayedPost, Seeds.PlaybackVideos.videos.first!.displayedPost) - XCTAssertEqual(spy.presentVideoListResponse.videos.last!.displayedPost, Seeds.PlaybackVideos.videos.last!.displayedPost) - } - } - - func test_moveInitialPlaybackCell을_호출하면_presentMoveInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다_parentView가_map일_때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.index = 2 - sut.presenter = spy - - // Act - sut.moveInitialPlaybackCell() - - // Assert - XCTAssertTrue(spy.presentMoveInitialPlaybackCellDidCalled, "moveInitialPlaybackCell은 moveInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveInitialPlaybackCellResponse.indexPathRow, 3) - } - - func test_moveInitialPlaybackCell을_호출하면_presentMoveInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다_parentView가_map이_아닐때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .home - sut.index = 2 - sut.presenter = spy - - // Act - sut.moveInitialPlaybackCell() - - // Assert - XCTAssertTrue(spy.presentMoveInitialPlaybackCellDidCalled, "moveInitialPlaybackCell은 moveInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveInitialPlaybackCellResponse.indexPathRow, 2) - } - - func test_setInitialPlaybackCell을_호출하면_presentSetInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다_parentView가_map일_때() { - // Arraynge - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.index = 2 - sut.presenter = spy - - // Act - sut.setInitialPlaybackCell() - - // Assert - XCTAssertTrue(spy.presentSetInitialPlaybackCellDidCalled, "setInitialPlaybackCell은 presentSetInitialPlaybackCell을 호출하지 않았습니다.") - XCTAssertEqual(spy.presentSetInitialPlaybackCellResponse.indexPathRow, 3) - } - - func test_setInitialPlaybackCell을_호출하면_presentSetInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다_parentView가_map이_아닐때() { - // Arraynge - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.index = 2 - sut.presenter = spy - - // Act - sut.setInitialPlaybackCell() - - // Assert - XCTAssertTrue(spy.presentSetInitialPlaybackCellDidCalled, "setInitialPlaybackCell은 presentSetInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentSetInitialPlaybackCellResponse.indexPathRow, 3) - } - - func test_playInitialPlaybackCell을_호출하면_presentPlayInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: nil, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - // Act - sut.playInitialPlaybackCell(with: request) - - // Assert - XCTAssertTrue(spy.presentPlayInitialPlaybackCellDidCalled, "playInitialPlaybackCell은 presentInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentPlayInitialPlaybackCellResponse.previousCell, nil) - XCTAssertEqual(spy.presentPlayInitialPlaybackCellResponse.currentCell, sut.previousCell) - XCTAssertEqual(spy.presentPlayInitialPlaybackCellResponse.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_playVideo를_호출할_때_이전Cell과_현재Cell이_동일하면_presentShowPlayerSlider를_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.videoURLNilPost] - sut.previousCell = Seeds.PlaybackVideo.currentCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: nil, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - // Act - sut.playVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentShowPlayerSliderDidCalled, "playVideo는 presentShowPlayerSlider를 호출하지 않았습니다") - XCTAssertEqual(spy.presentShowPlayerSliderResponse.currentCell, request.currentCell) - } - - func test_parentView가_map이고_index가_마지막을_가리킬_떄_playVideo를_호출하면_presentMoveCellNext를_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2] - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: 1, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - // act - sut.playVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "playVideo는 presentTeleportCell를 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveCellNextResponse.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertFalse(sut.isTeleport!) - } - - func test_parentView가_map이고_index가_처음을_가리킬_떄_playVideo를_호출하면_presentMoveCellNext를_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2] - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: 1, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - // act - sut.playVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "playVideo는 presentTeleportCell를 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveCellNextResponse.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.currentCell, Seeds.PlaybackVideo.currentCell) - XCTAssertFalse(sut.isTeleport!) - } - - func test_playVideo를_호출하면_presentMoveCellNext를_호출한다_parentView가_map이고_텔레포트가_필요없는_상황일_때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .map - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost] - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: 1, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - - // act - sut.playVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "playVideo는 presentMoveCellNext를 호출하지 않았습니다") - XCTAssertEqual(sut.previousCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.currentCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.indexPathRow, nil) - if let isTeleport = sut.isTeleport { - XCTAssertFalse(isTeleport) - } else { - XCTFail() - } - } - - func test_playTeleportVideo를_호출하면_presentMoveCellNext를_호출한다_무한스크롤상황일_때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost] - sut.isTeleport = true - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: 1, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - - // act - sut.playTeleportVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "playTeleportvideo는 presentMoveCellNext를 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveCellNextResponse.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.currentCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(sut.previousCell, Seeds.PlaybackVideo.currentCell) - if let isTeleport = sut.isTeleport { - XCTAssertFalse(isTeleport) - } else { - XCTFail() - } - } - - func test_playTeleportVideo를_호출하면_presentMoveCellNext를_호출한다_셀이_삭제되는_상황일_때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost] - sut.isDelete = true - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: 1, currentCell: Seeds.PlaybackVideo.currentCell) - sut.presenter = spy - // act - sut.playTeleportVideo(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "playTeleportvideo는 presentMoveCellNext를 호출하지 않았습니다") - XCTAssertNil(spy.presentMoveCellNextResponse.previousCell) - XCTAssertEqual(spy.presentMoveCellNextResponse.currentCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(sut.previousCell, Seeds.PlaybackVideo.currentCell) - XCTAssertFalse(sut.isDelete!) - } - - func test_resumePlaybackView를_호출할때_previousCell이_존재하면_presentPlayInitialPlaybackCell을_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.presenter = spy - - // act - sut.resumePlaybackView() - - // Assert - XCTAssertTrue(spy.presentPlayInitialPlaybackCellDidCalled, "resumPlaybackView가 presentPlayInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentPlayInitialPlaybackCellResponse.currentCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.presentPlayInitialPlaybackCellResponse.previousCell, nil) - } - - func test_resumePlaybackView를_호출할때_previousCell이_존재하면_presentSetInitialPlaybackCell을_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.index = 2 - sut.presenter = spy - - // act - sut.resumePlaybackView() - - // Assert - XCTAssertTrue(spy.presentSetInitialPlaybackCellDidCalled, "resumPlaybackView가 presentSetInitialPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentSetInitialPlaybackCellResponse.indexPathRow, 2) - } - - func test_leavePlaybackView를_호출할때_presentLeavePlaybackView를_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.presenter = spy - // act - sut.leavePlaybackView() - - // Assert - XCTAssertTrue(spy.presentLeavePlaybackViewDidCalled, "leavePlaybackView가 presentLeavePlaybackView를 호출하지 않았습니다") - XCTAssertEqual(spy.presentLeavePlaybackViewResponse.previousCell, Seeds.PlaybackVideo.previousCell) - } - - func test_resetVideo를_호출할때_presentResetPlaybackCell을_호출한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.presenter = spy - // act - sut.resetVideo() - - // Assert - XCTAssertTrue(spy.presentResetPlaybackCellDidCalled, "resetVideo가 presentResetPlaybackCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentResetPlaybackCellResponse.previousCell, nil) - XCTAssertEqual(spy.presentResetPlaybackCellResponse.currentCell, Seeds.PlaybackVideo.previousCell) - } - - func test_careVideoLoading을_호출할때_presentMoveCellNext를_호출하지않는다_previousCell이_존재할때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: nil, currentCell: nil) - // act - sut.careVideoLoading(with: request) - - // Assert - XCTAssertFalse(spy.presentMoveCellNextDidCalled, "careVideoLoading은 presentMoveCellNext를 호출하지 않았습니다") - } - - func test_careVideoLoading을_호출할때_presentMoveCellNext를_호출하지않는다_previousCell이_존재하지않을때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = nil - sut.presenter = spy - let request: Models.DisplayPlaybackVideo.Request = Models.DisplayPlaybackVideo.Request(indexPathRow: nil, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.careVideoLoading(with: request) - - // Assert - XCTAssertTrue(spy.presentMoveCellNextDidCalled, "careVideoLoading은 presentMoveCellNext를 호출하지 않았습니다") - XCTAssertEqual(spy.presentMoveCellNextResponse.previousCell, nil) - XCTAssertEqual(spy.presentMoveCellNextResponse.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_configurePlaybackCell을_호출할때_presentConfigureCell을_호출한다_map일때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost] - sut.parentView = .map - sut.presenter = spy - - // act - sut.configurePlaybackCell() - - // Assert - XCTAssertTrue(spy.presentConfigureCellDidCalled, "configurePlaybackCell은 presentConfigureCell을 호출하지 않았습니다") - XCTAssertEqual(spy.presentConfigureCellResponse.teleportIndex, 4) - } - - func test_configurePlaybackCell을_호출할때_presentConfigureCell을_호출한다_map이_아닐때() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost] - sut.parentView = .home - sut.presenter = spy - - // act - sut.configurePlaybackCell() - - // Assert - XCTAssertTrue(spy.presentConfigureCellDidCalled, "configurePlaybackCell은 presentConfigureCell을 호출하지 않았습니다") - } - - func test_setSeemoreButton을_호출할때_presentSetSeemoreButton을_호출하고_올바른_데이터를_전달한다_본인일경우() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: -1, boardID: -1)] - sut.presenter = spy - - // act - sut.setSeeMoreButton(with: Models.SetSeemoreButton.Request(indexPathRow: 0)) - - // Assert - XCTAssertTrue(spy.presentSetSeemoreButtonDidCalled, "") - XCTAssertEqual(spy.presentSetSeemoreButtonResponse.buttonType, .delete) - } - - func test_본인이아닐경우_setSeemoreButton을_호출할때_presentSetSeemoreButton을_호출하고_올바른_데이터를_전달한다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.previousCell = Seeds.PlaybackVideo.previousCell - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 1, boardID: -1)] - sut.presenter = spy - - // act - sut.setSeeMoreButton(with: Models.SetSeemoreButton.Request(indexPathRow: 0)) - - // Assert - XCTAssertTrue(spy.presentSetSeemoreButtonDidCalled, "") - XCTAssertEqual(spy.presentSetSeemoreButtonResponse.buttonType, .report) - } - - func test_moveToProfile을_호출할때_presentProfile이_호출된다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let request: Models.MoveToRelativeView.Request = Models.MoveToRelativeView.Request(indexPathRow: 0, selectedTag: "테스트") - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 1, boardID: -1)] - sut.presenter = spy - - // act - sut.moveToProfile(with: request) - - // Assert - XCTAssertTrue(spy.presentProfileDidCalled, "moveToProfile이 presentProfileDidCalled를 호출하지 않았습니다") - XCTAssertEqual(sut.memberID, 1) - } - - func test_moveToTagPlay를_호출할때_presentTagPlay가_호출된다() { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let request: Models.MoveToRelativeView.Request = Models.MoveToRelativeView.Request(indexPathRow: 0, selectedTag: "테스트") - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 1, boardID: -1)] - sut.presenter = spy - - // act - sut.moveToTagPlay(with: request) - - // Assert - XCTAssertTrue(spy.presentTagPlayDidCalled, "moveToTagPlay이 presentTagPlay를 호출하지 않았습니다") - XCTAssertEqual(sut.selectedTag, "테스트") - } - - func test_Home_fetchPosts를_호출하면_presentLoadFetchVideosResponse를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .home - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2] - sut.presenter = spy - - // act - await sut.fetchPosts() - - // Assert - XCTAssertTrue(spy.presentLoadFetchVideosDidCalled, "fetchPosts가 presentLoadFetchVideos를 호출하지 않았습니다") - XCTAssertEqual(spy.presentLoadFetchVideosResponse.videos.count, 1) - XCTAssertEqual(sut.posts?.count, 3) - } - - func test_tag_fetchPosts를_호출하면_presentLoadFetchVideos를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .tag - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2] - sut.playbackVideoInfos = [ - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0) - ] - sut.selectedTag = "테스트" - sut.presenter = spy - - // act - await sut.fetchPosts() - - // Assert - XCTAssertTrue(spy.presentLoadFetchVideosDidCalled, "fetchPosts가 presentLoadFetchVideos를 호출하지 않았습니다") - XCTAssertEqual(spy.presentLoadFetchVideosResponse.videos.count, 1) - XCTAssertEqual(sut.posts?.count, 21) - XCTAssertEqual(sut.playbackVideoInfos.count, 21) - } - - func test_Profile_fetchPosts를_호출하면_presentLoadFetchVideos를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - sut.parentView = .otherProfile - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.post1, Seeds.Posts.post2] - sut.playbackVideoInfos = [ - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0), - Models.PlaybackInfo(memberID: 0, boardID: 0), Models.PlaybackInfo(memberID: 0, boardID: 0) - ] - - sut.presenter = spy - sut.memberID = -1 - - // act - await sut.fetchPosts() - - // Assert - XCTAssertTrue(spy.presentLoadFetchVideosDidCalled, "fetchPosts가 presentLoadFetchVideos를 호출하지 않았습니다") - XCTAssertEqual(spy.presentLoadFetchVideosResponse.videos.count, 1) - XCTAssertEqual(sut.posts?.count, 21) - } - - func test_map이_아닐_때_deleteVideo를_호출하면_presentDeleteVideo를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let testPost: Post = Seeds.Posts.post1 - let playbackVideo: Models.PlaybackVideo = Models.PlaybackVideo( - displayedPost: Models.DisplayedPost( - member: Models.Member( - memberID: testPost.member.identifier, - username: testPost.member.username, - profileImageURL: testPost.member.profileImageURL), - board: Models.Board( - boardID: testPost.board.identifier, - title: testPost.board.title, - description: testPost.board.description, - videoURL: testPost.board.videoURL!, - latitude: testPost.board.latitude, - longitude: testPost.board.longitude), - tags: Seeds.Posts.post1.tag)) - sut.parentView = .home - sut.presenter = spy - sut.posts = [Seeds.Posts.post1, Seeds.Posts.post2] - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 0, boardID: 1), Models.PlaybackInfo(memberID: 0, boardID: 2)] - - // act - await sut.deleteVideo(with: Models.DeletePlaybackVideo.Request(playbackVideo: playbackVideo, indexPathRow: 0)) - - // Assert - XCTAssertTrue(spy.presentDeleteVideoDidCalled, "deleteVideo가 presentDeleteVideo를 호출하지 않았습니다") - XCTAssertTrue(spy.presentDeleteVideoResponse.result, "result 결과가 옳지 않습니다.") - XCTAssertEqual(spy.presentDeleteVideoResponse.playbackVideo, playbackVideo) - XCTAssertEqual(sut.posts!.count, 1) - XCTAssertEqual(sut.playbackVideoInfos.count, 1) - } - - // TODO: map paging추가되면 로직 그냥 날려버리기 - - func test_map일_때_마지막_무한스크롤셀을_지울_경우_deleteVideo를_호출하면_presentDeleteVideo를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let testPost: Post = Seeds.Posts.post1 - let playbackVideo: Models.PlaybackVideo = Models.PlaybackVideo( - displayedPost: Models.DisplayedPost( - member: Models.Member( - memberID: testPost.member.identifier, - username: testPost.member.username, - profileImageURL: testPost.member.profileImageURL), - board: Models.Board( - boardID: testPost.board.identifier, - title: testPost.board.title, - description: testPost.board.description, - videoURL: testPost.board.videoURL!, - latitude: testPost.board.latitude, - longitude: testPost.board.longitude), - tags: Seeds.Posts.post1.tag)) - sut.parentView = .map - sut.presenter = spy - sut.posts = [Seeds.Posts.thumbnailImageNilPost, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost ,Seeds.Posts.post1] - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1), Models.PlaybackInfo(memberID: 0, boardID: 2), Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1)] - - // act - await sut.deleteVideo(with: Models.DeletePlaybackVideo.Request(playbackVideo: playbackVideo, indexPathRow: 3)) - - // assert - XCTAssertTrue(spy.presentDeleteVideoDidCalled, "deleteVideo가 presentDeleteVideo를 호출하지 않았습니다") - XCTAssertEqual(sut.playbackVideoInfos[0].boardID, 1) - XCTAssertEqual(sut.playbackVideoInfos[1].boardID, 2) - XCTAssertEqual(sut.playbackVideoInfos[2].boardID, 1) - XCTAssertEqual(sut.playbackVideoInfos[3].boardID, 2) - XCTAssertEqual(sut.posts?[0].board.identifier, Seeds.Posts.post1.board.identifier) - XCTAssertEqual(sut.posts?[1].board.identifier, Seeds.Posts.post2.board.identifier) - XCTAssertEqual(sut.posts?[2].board.identifier, Seeds.Posts.post1.board.identifier) - XCTAssertEqual(sut.posts?[3].board.identifier, Seeds.Posts.post2.board.identifier) - XCTAssertEqual(sut.playbackVideoInfos.count, 4) - XCTAssertEqual(sut.posts?.count, 4) - } - - func test_map일_때_첫번째_무한스크롤셀을_지울_경우_deleteVideo를_호출하면_presentDeleteVideo를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let testPost: Post = Seeds.Posts.post1 - let playbackVideo: Models.PlaybackVideo = Models.PlaybackVideo( - displayedPost: Models.DisplayedPost( - member: Models.Member( - memberID: testPost.member.identifier, - username: testPost.member.username, - profileImageURL: testPost.member.profileImageURL), - board: Models.Board( - boardID: testPost.board.identifier, - title: testPost.board.title, - description: testPost.board.description, - videoURL: testPost.board.videoURL!, - latitude: testPost.board.latitude, - longitude: testPost.board.longitude), - tags: Seeds.Posts.post1.tag)) - sut.parentView = .map - sut.presenter = spy - sut.posts = [Seeds.Posts.thumbnailImageNilPost, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost ,Seeds.Posts.post1] - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1), Models.PlaybackInfo(memberID: 0, boardID: 2), Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1)] - - // act - await sut.deleteVideo(with: Models.DeletePlaybackVideo.Request(playbackVideo: playbackVideo, indexPathRow: 1)) - - // assert - XCTAssertTrue(spy.presentDeleteVideoDidCalled, "deleteVideo가 presentDeleteVideo를 호출하지 않았습니다") - XCTAssertEqual(sut.playbackVideoInfos[0].boardID, 3) - XCTAssertEqual(sut.playbackVideoInfos[1].boardID, 2) - XCTAssertEqual(sut.playbackVideoInfos[2].boardID, 3) - XCTAssertEqual(sut.playbackVideoInfos[3].boardID, 2) - XCTAssertEqual(sut.posts?[0].board.identifier, Seeds.Posts.thumbnailImageNilPost.board.identifier) - XCTAssertEqual(sut.posts?[1].board.identifier, Seeds.Posts.post2.board.identifier) - XCTAssertEqual(sut.posts?[2].board.identifier, Seeds.Posts.thumbnailImageNilPost.board.identifier) - XCTAssertEqual(sut.posts?[3].board.identifier, Seeds.Posts.post2.board.identifier) - XCTAssertEqual(sut.playbackVideoInfos.count, 4) - XCTAssertEqual(sut.posts?.count, 4) - } - - func test_map일_때_무한스크롤셀을_지우지않을_경우_deleteVideo를_호출하면_presentDeleteVideo를_호출한다() async { - // Arrange - let spy = PlaybackPresentationLogicSpy() - let testPost: Post = Seeds.Posts.post1 - let playbackVideo: Models.PlaybackVideo = Models.PlaybackVideo( - displayedPost: Models.DisplayedPost( - member: Models.Member( - memberID: testPost.member.identifier, - username: testPost.member.username, - profileImageURL: testPost.member.profileImageURL), - board: Models.Board( - boardID: testPost.board.identifier, - title: testPost.board.title, - description: testPost.board.description, - videoURL: testPost.board.videoURL!, - latitude: testPost.board.latitude, - longitude: testPost.board.longitude), - tags: Seeds.Posts.post1.tag)) - sut.parentView = .map - sut.presenter = spy - sut.posts = [Seeds.Posts.thumbnailImageNilPost, Seeds.Posts.post1, Seeds.Posts.post2, Seeds.Posts.thumbnailImageNilPost ,Seeds.Posts.post1] - sut.playbackVideoInfos = [Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1), Models.PlaybackInfo(memberID: 0, boardID: 2), Models.PlaybackInfo(memberID: 0, boardID: 3), Models.PlaybackInfo(memberID: 0, boardID: 1)] - - // act - await sut.deleteVideo(with: Models.DeletePlaybackVideo.Request(playbackVideo: playbackVideo, indexPathRow: 2)) - - // assert - XCTAssertTrue(spy.presentDeleteVideoDidCalled, "deleteVideo가 presentDeleteVideo를 호출하지 않았습니다") - XCTAssertEqual(sut.playbackVideoInfos[0].boardID, 3) - XCTAssertEqual(sut.playbackVideoInfos[1].boardID, 1) - XCTAssertEqual(sut.playbackVideoInfos[2].boardID, 3) - XCTAssertEqual(sut.playbackVideoInfos[3].boardID, 1) - XCTAssertEqual(sut.posts?[0].board.identifier, Seeds.Posts.thumbnailImageNilPost.board.identifier) - XCTAssertEqual(sut.posts?[1].board.identifier, Seeds.Posts.post1.board.identifier) - XCTAssertEqual(sut.posts?[2].board.identifier, Seeds.Posts.thumbnailImageNilPost.board.identifier) - XCTAssertEqual(sut.posts?[3].board.identifier, Seeds.Posts.post1.board.identifier) - XCTAssertEqual(sut.playbackVideoInfos.count, 4) - XCTAssertEqual(sut.posts?.count, 4) - } -} diff --git a/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackPresenterTests.swift b/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackPresenterTests.swift deleted file mode 100644 index 51111fa4..00000000 --- a/iOS/Layover/LayoverTests/Mocks/Workers/PlaybackPresenterTests.swift +++ /dev/null @@ -1,417 +0,0 @@ -// -// PlaybackPresenterTests.swift -// LayoverTests -// -// Created by 황지웅 on 12/12/23. -// Copyright © 2023 CodeBomber. All rights reserved. -// - -@testable import Layover -import XCTest - -final class PlaybackPresenterTests: XCTestCase { - // MARK: Subject under test - - var sut: PlaybackPresenter! - - typealias Models = PlaybackModels - - // MARK: - Test lifecycle - - override func setUp() { - super.setUp() - setupPlaybackPresenter() - - } - - override func tearDown() { - super.tearDown() - } - - // MARK: - Test setup - - func setupPlaybackPresenter() { - sut = PlaybackPresenter() - } - - // MARK: - Test doubles - - final class PlaybackDisplayLogicSpy: PlaybackDisplayLogic { - var displayVideoListDidCalled = false - var displayVideoListViewModel: Models.LoadPlaybackVideoList.ViewModel! - - var loadFetchVideosDidCalled = false - var loadFetchVideosViewModel: Models.LoadPlaybackVideoList.ViewModel! - - var setInitialPlaybackCellDidCalled = false - var setInitialPlaybackCellViewModel: Models.SetInitialPlaybackCell.ViewModel! - - var moveInitialPlaybackCellDidCalled = false - var moveInitialPlaybackCellViewModel: Models.SetInitialPlaybackCell.ViewModel! - - var stopPrevPlayerAndPlayCurPlayerDidCalled = false - var stopPrevPlayerAndPlayCurPlayerViewModel: Models.DisplayPlaybackVideo.ViewModel! - - var showPlayerSliderDidCalled = false - var showPlayerSliderViewModel: Models.DisplayPlaybackVideo.ViewModel! - - var teleportPlaybackCellDidCalled = false - var teleportPlaybackCellViewModel: Models.DisplayPlaybackVideo.ViewModel! - - var leavePlaybackViewDidCalled = false - var leavePlaybackViewViewModel: Models.DisplayPlaybackVideo.ViewModel! - - var resetVideoDidCalled = false - var resetVideoViewModel: Models.DisplayPlaybackVideo.ViewModel! - - var configureDataSourceDidCalled = false - var configureDataSourceViewModel: Models.ConfigurePlaybackCell.ViewModel! - - var setSeemoreButtonDidCalled = false - var setSeemoreButtonViewModel: Models.SetSeemoreButton.ViewModel! - - var deleteVideoDidCalled = false - var deleteVideoViewModel: Models.DeletePlaybackVideo.ViewModel! - - var routeToProfileDidCalled = false - - var routeToTagPlayDidCalled = false - - var setProfileImageAndLocationDidCalled = false - var setProfileImageAndLocationViewModel: Models.LoadProfileImageAndLocation.ViewModel! - - var seekVideoDidCalled = false - var seekVideoViewModel: Models.SeekVideo.ViewModel! - - var reportVideoDidCalled = false - - func displayVideoList(viewModel: Layover.PlaybackModels.LoadPlaybackVideoList.ViewModel) { - displayVideoListDidCalled = true - displayVideoListViewModel = viewModel - } - - func loadFetchVideos(viewModel: Layover.PlaybackModels.LoadPlaybackVideoList.ViewModel) { - loadFetchVideosDidCalled = true - loadFetchVideosViewModel = viewModel - } - - func setInitialPlaybackCell(viewModel: Layover.PlaybackModels.SetInitialPlaybackCell.ViewModel) { - setInitialPlaybackCellDidCalled = true - setInitialPlaybackCellViewModel = viewModel - } - - func moveInitialPlaybackCell(viewModel: Layover.PlaybackModels.SetInitialPlaybackCell.ViewModel) { - moveInitialPlaybackCellDidCalled = true - moveInitialPlaybackCellViewModel = viewModel - } - - func stopPrevPlayerAndPlayCurPlayer(viewModel: Layover.PlaybackModels.DisplayPlaybackVideo.ViewModel) { - stopPrevPlayerAndPlayCurPlayerDidCalled = true - stopPrevPlayerAndPlayCurPlayerViewModel = viewModel - } - - func showPlayerSlider(viewModel: Layover.PlaybackModels.DisplayPlaybackVideo.ViewModel) { - showPlayerSliderDidCalled = true - showPlayerSliderViewModel = viewModel - } - - func teleportPlaybackCell(viewModel: Layover.PlaybackModels.DisplayPlaybackVideo.ViewModel) { - teleportPlaybackCellDidCalled = true - teleportPlaybackCellViewModel = viewModel - } - - func leavePlaybackView(viewModel: Layover.PlaybackModels.DisplayPlaybackVideo.ViewModel) { - leavePlaybackViewDidCalled = true - leavePlaybackViewViewModel = viewModel - } - - func resetVideo(viewModel: Layover.PlaybackModels.DisplayPlaybackVideo.ViewModel) { - resetVideoDidCalled = true - resetVideoViewModel = viewModel - } - - func configureDataSource(viewModel: Layover.PlaybackModels.ConfigurePlaybackCell.ViewModel) { - configureDataSourceDidCalled = true - configureDataSourceViewModel = viewModel - } - - func setSeemoreButton(viewModel: Layover.PlaybackModels.SetSeemoreButton.ViewModel) { - setSeemoreButtonDidCalled = true - setSeemoreButtonViewModel = viewModel - } - - func deleteVideo(viewModel: Layover.PlaybackModels.DeletePlaybackVideo.ViewModel) { - deleteVideoDidCalled = true - deleteVideoViewModel = viewModel - } - - func routeToProfile() { - routeToProfileDidCalled = true - } - - func routeToTagPlay() { - routeToTagPlayDidCalled = true - } - - func setProfileImageAndLocation(viewModel: Layover.PlaybackModels.LoadProfileImageAndLocation.ViewModel) { - setProfileImageAndLocationDidCalled = true - setProfileImageAndLocationViewModel = viewModel - } - - func seekVideo(viewModel: Layover.PlaybackModels.SeekVideo.ViewModel) { - seekVideoDidCalled = true - seekVideoViewModel = viewModel - } - - func reportVideo() { - reportVideoDidCalled = true - } - } - - // MARK: - Tests - - func test_presentVideoList를_호출하면_displayVideoList를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.LoadPlaybackVideoList.Response = Models.LoadPlaybackVideoList.Response(videos: Seeds.PlaybackVideos.videos) - - // act - sut.presentVideoList(with: response) - - // assert - XCTAssertTrue(spy.displayVideoListDidCalled, "presentProfile은 displayVideoList를 호출했다") - // videos는 Hashable - XCTAssertEqual(spy.displayVideoListViewModel.videos.first!, Seeds.PlaybackVideos.videos.first!) - XCTAssertEqual(spy.displayVideoListViewModel.videos.last!, Seeds.PlaybackVideos.videos.last!) - XCTAssertEqual(spy.displayVideoListViewModel.videos.count, 2) - } - - func test_presentLoadFetchVideos를_호출하면_loadFetchVideos를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.LoadPlaybackVideoList.Response = Models.LoadPlaybackVideoList.Response(videos: Seeds.PlaybackVideos.videos) - // act - sut.presentLoadFetchVideos(with: response) - - // assert - XCTAssertTrue(spy.loadFetchVideosDidCalled, "presentLoadFetchVideos는 loadFetchVideos를 호출했다") - XCTAssertEqual(spy.loadFetchVideosViewModel.videos.first!, Seeds.PlaybackVideos.videos.first!) - XCTAssertEqual(spy.loadFetchVideosViewModel.videos.last!, Seeds.PlaybackVideos.videos.last!) - XCTAssertEqual(spy.loadFetchVideosViewModel.videos.count, 2) - } - - func test_presentSetInitialPlaybackCell을_호출하면_setInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.SetInitialPlaybackCell.Response = Models.SetInitialPlaybackCell.Response(indexPathRow: 1) - // act - sut.presentSetInitialPlaybackCell(with: response) - - // assert - XCTAssertTrue(spy.setInitialPlaybackCellDidCalled, "presentSetInitialPlaybackCell은 setInitialPlaybackCell을 호출했다") - XCTAssertEqual(spy.setInitialPlaybackCellViewModel.indexPathRow, 1) - } - - func test_presentMoveInitialPlaybackCell을_호출하면_moveInitialPlaybackCell을_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.SetInitialPlaybackCell.Response = Models.SetInitialPlaybackCell.Response(indexPathRow: 1) - // act - sut.presentMoveInitialPlaybackCell(with: response) - - // assert - XCTAssertTrue(spy.moveInitialPlaybackCellDidCalled, "presentMoveInitialPlaybackCell은 moveInitialPlaybackCell을 호출했다") - XCTAssertEqual(spy.moveInitialPlaybackCellViewModel.indexPathRow, 1) - } - - func test_presentMoveCellNext를_호출하면_stopPrevPlayerAndPlayCurPlayer를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(previousCell: Seeds.PlaybackVideo.previousCell, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.presentMoveCellNext(with: response) - - // assert - XCTAssertTrue(spy.stopPrevPlayerAndPlayCurPlayerDidCalled, "presentMoveCellNext는 stopPrevPlayerAndPlayCurPlayerDidCalled를 호출했다") - // 이전 PlaybackCell과 현재 PlaybackCell은 달라야함 - XCTAssertNotEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.previousCell, spy.stopPrevPlayerAndPlayCurPlayerViewModel.currentCell) - XCTAssertEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_presentPlayInitialPlaybackCell을_호출하면_stopPrevPlayerAndPlayCurPlayer를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(previousCell: nil, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.presentPlayInitialPlaybackCell(with: response) - - // assert - XCTAssertTrue(spy.stopPrevPlayerAndPlayCurPlayerDidCalled, "presentPlayInitialPlaybackCell은 stopPrevPlayerAndPlayCurPlayerDidCalled를 호출했다") - XCTAssertNotEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.previousCell, spy.stopPrevPlayerAndPlayCurPlayerViewModel.currentCell) - XCTAssertEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.previousCell, nil) - XCTAssertEqual(spy.stopPrevPlayerAndPlayCurPlayerViewModel.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_presentShowPlayerSlider를_호출하면_showPlayerSlider를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(previousCell: nil, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.presentShowPlayerSlider(with: response) - - // assert - XCTAssertTrue(spy.showPlayerSliderDidCalled, "presentShowPlayerSlider은 showPlayerSlider를 호출했다") - XCTAssertNotEqual(spy.showPlayerSliderViewModel.previousCell, spy.showPlayerSliderViewModel.currentCell) - XCTAssertEqual(spy.showPlayerSliderViewModel.previousCell, nil) - XCTAssertEqual(spy.showPlayerSliderViewModel.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_presentTeleportCell을_호출하면_teleportPlaybackCell을_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(indexPathRow: 3, previousCell: nil, currentCell: nil) - // act - sut.presentTeleportCell(with: response) - - // assert - XCTAssertTrue(spy.teleportPlaybackCellDidCalled, "presentTeleportCell은 teleportPlaybackCell을 호출하지 못했습니다") - XCTAssertEqual(spy.teleportPlaybackCellViewModel.indexPathRow, 3) - } - - func test_presentLeavePlaybackView를_호출하면_leavePlaybackView를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(previousCell: Seeds.PlaybackVideo.previousCell, currentCell: nil) - // act - sut.presentLeavePlaybackView(with: response) - - // assert - XCTAssertTrue(spy.leavePlaybackViewDidCalled, "presentLeavePlaybackView는 teleportPlaybackCell을 호출하지 못했습니다") - XCTAssertNotEqual(spy.leavePlaybackViewViewModel.previousCell, spy.leavePlaybackViewViewModel.currentCell) - XCTAssertEqual(spy.leavePlaybackViewViewModel.previousCell, Seeds.PlaybackVideo.previousCell) - XCTAssertEqual(spy.leavePlaybackViewViewModel.currentCell, nil) - } - - func test_presentResetPlaybackCell을_호출하면_resetVideo를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.DisplayPlaybackVideo.Response = Models.DisplayPlaybackVideo.Response(previousCell: nil, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.presentResetPlaybackCell(with: response) - - // assert - XCTAssertTrue(spy.resetVideoDidCalled, "presentResetPlaybackCell은 resetVideo를 호출하지 못했습니다") - XCTAssertNotEqual(spy.resetVideoViewModel.previousCell, spy.resetVideoViewModel.currentCell) - XCTAssertEqual(spy.resetVideoViewModel.previousCell, nil) - XCTAssertEqual(spy.resetVideoViewModel.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_presentConfigureCell을_호출하면_configureDataSource를_호출하고_올바른_데이터를_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.ConfigurePlaybackCell.Response = Models.ConfigurePlaybackCell.Response(teleportIndex: 3) - // act - sut.presentConfigureCell(with: response) - - // assert - XCTAssertTrue(spy.configureDataSourceDidCalled, "presentConfigureDataSource는 configureDataSource를 호출하지 못했습니다") - XCTAssertEqual(spy.configureDataSourceViewModel.teleportIndex, 3) - } - - func test_presentSetSeemoreButton을_호출하면_setSeemoreButton을_호출하고_올바른_데이터를_전달한다_delete() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.SetSeemoreButton.Response = Models.SetSeemoreButton.Response(buttonType: .delete, indexPathRow: 0) - // act - sut.presentSetSeemoreButton(with: response) - - // assert - XCTAssertTrue(spy.setSeemoreButtonDidCalled, "presentSetSeemoreButton은 setSeemoreButton을 호출하지 못했습니다") - XCTAssertEqual(spy.setSeemoreButtonViewModel.buttonType, .delete) - } - - func test_presentSetSeemoreButton을_호출하면_setSeemoreButton을_호출하고_올바른_데이터를_전달한다_report() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.SetSeemoreButton.Response = Models.SetSeemoreButton.Response(buttonType: .report, indexPathRow: 0) - // act - sut.presentSetSeemoreButton(with: response) - - // assert - XCTAssertTrue(spy.setSeemoreButtonDidCalled, "presentSetSeemoreButton은 setSeemoreButton을 호출하지 못했습니다") - XCTAssertEqual(spy.setSeemoreButtonViewModel.buttonType, .report) - } - - func test_presentProfile을_호출하면_routeToProfile을_호출한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - // act - sut.presentProfile() - - // assert - XCTAssertTrue(spy.routeToProfileDidCalled, "presentProfile은 routeToProfile을 호출하지 못했습니다") - } - - func test_presentTagPlay을_호출하면_routeToTagPlay을_호출한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - // act - sut.presentTagPlay() - - // assert - XCTAssertTrue(spy.routeToTagPlayDidCalled, "presentTagPlay는 routeToTagPlay를 호출하지 못했습니다") - } - - func test_presentLoadProfileImageAndLocation을_호출하면_setProfileImageAndLocation을_호출한다_nil일_경우_지역으로_이름_모를_곳을_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.LoadProfileImageAndLocation.Response = Models.LoadProfileImageAndLocation.Response(curCell: Seeds.PlaybackVideo.currentCell, profileImageData: Seeds.PlaybackVideo.profileImageData, location: nil) - // act - sut.presentLoadProfileImageAndLocation(with: response) - - // assert - XCTAssertTrue(spy.setProfileImageAndLocationDidCalled, "presentLoadProfileImageAndLocation은 setProfileImageAndLocation를 호출하지 못했습니다") - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.curCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.profileImageData, Seeds.PlaybackVideo.profileImageData) - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.location, "이름 모를 곳") - } - - func test_presentLoadProfileImageAndLocation을_호출하면_setProfileImageAndLocation을_호출한다_지역이_존재할_경우_지역으로_지역이름을_전달한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.LoadProfileImageAndLocation.Response = Models.LoadProfileImageAndLocation.Response(curCell: Seeds.PlaybackVideo.currentCell, profileImageData: Seeds.PlaybackVideo.profileImageData, location: "서울특별시") - // act - sut.presentLoadProfileImageAndLocation(with: response) - - // assert - XCTAssertTrue(spy.setProfileImageAndLocationDidCalled, "presentLoadProfileImageAndLocation은 setProfileImageAndLocation를 호출하지 못했습니다") - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.curCell, Seeds.PlaybackVideo.currentCell) - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.profileImageData, Seeds.PlaybackVideo.profileImageData) - XCTAssertEqual(spy.setProfileImageAndLocationViewModel.location, "서울특별시") - } - - func test_presentSeekVideo를_호출하면_seekVideo를_호출한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - let response: Models.SeekVideo.Response = Models.SeekVideo.Response(willMoveLocation: 1, currentCell: Seeds.PlaybackVideo.currentCell) - // act - sut.presentSeekVideo(with: response) - - // assert - XCTAssertTrue(spy.seekVideoDidCalled, "presentSeekVideo를 호출하지 못했습니다.") - XCTAssertEqual(spy.seekVideoViewModel.willMoveLocation, 1) - XCTAssertEqual(spy.seekVideoViewModel.currentCell, Seeds.PlaybackVideo.currentCell) - } - - func test_presentReportVideo를_호출하면_reportVideo를_호출한다() { - let spy = PlaybackDisplayLogicSpy() - sut.viewController = spy - - // act - sut.presentReportVideo() - - // assert - XCTAssertTrue(spy.reportVideoDidCalled, "presentReportVideo를 호출하지 못했습니다") - } -} diff --git a/iOS/Layover/LayoverTests/Scenes/Home/HomeInteractorTests.swift b/iOS/Layover/LayoverTests/Scenes/Home/HomeInteractorTests.swift index 94c6dbfe..88473d92 100644 --- a/iOS/Layover/LayoverTests/Scenes/Home/HomeInteractorTests.swift +++ b/iOS/Layover/LayoverTests/Scenes/Home/HomeInteractorTests.swift @@ -36,6 +36,10 @@ final class HomeInteractorTests: XCTestCase { // MARK: - Test doubles final class HomePresentationLogicSpy: HomePresentationLogic { + func presentMorePosts(with response: Layover.HomeModels.FetchPosts.Response) { + + } + func presentUploadScene() { } @@ -77,20 +81,45 @@ final class HomeInteractorTests: XCTestCase { // Assert XCTAssertTrue(spy.presentPostsCalled, "fetchPost()가 presenter의 presentPosts()를 호출하지 못했다.") XCTAssertEqual(spy.presentPostsReceivedResponse.posts.count, 1, "fetchPost()가 presenter에게 올바른 데이터 갯수를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].tag, Seeds.Posts.post1.tag, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].thumbnailImageData, Seeds.sampleImageData, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.identifier, Seeds.Posts.post1.board.identifier, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.title, Seeds.Posts.post1.board.title, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.description, Seeds.Posts.post1.board.description, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.latitude, Seeds.Posts.post1.board.latitude, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.longitude, Seeds.Posts.post1.board.longitude, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.thumbnailImageURL, Seeds.Posts.post1.board.thumbnailImageURL, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.videoURL, Seeds.Posts.post1.board.videoURL, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.status, Seeds.Posts.post1.board.status, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.username, Seeds.Posts.post1.member.username, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.introduce, Seeds.Posts.post1.member.introduce, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.profileImageURL, Seeds.Posts.post1.member.profileImageURL, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") - XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.identifier, Seeds.Posts.post1.member.identifier, "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].tag, + Seeds.PostsPage.post1.tag, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.identifier, + Seeds.PostsPage.post1.board.identifier, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.title, + Seeds.PostsPage.post1.board.title, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.description, + Seeds.PostsPage.post1.board.description, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.latitude, + Seeds.PostsPage.post1.board.latitude, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.longitude, + Seeds.PostsPage.post1.board.longitude, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.thumbnailImageURL, + Seeds.PostsPage.post1.board.thumbnailImageURL, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.videoURL, + Seeds.PostsPage.post1.board.videoURL, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].board.status, + Seeds.PostsPage.post1.board.status, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.username, + Seeds.PostsPage.post1.member.username, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.introduce, + Seeds.PostsPage.post1.member.introduce, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.profileImageURL, + Seeds.PostsPage.post1.member.profileImageURL, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") + XCTAssertEqual(spy.presentPostsReceivedResponse.posts[0].member.identifier, + Seeds.PostsPage.post1.member.identifier, + "fetchPost()가 presenter에게 올바른 데이터를 저장하지 못했다.") } func test_playPosts는_자신의_selectedIndex값을_변경한다() { diff --git a/iOS/Layover/LayoverTests/Scenes/Home/HomePresenterTests.swift b/iOS/Layover/LayoverTests/Scenes/Home/HomePresenterTests.swift index 35bfd4f9..c90ddd33 100644 --- a/iOS/Layover/LayoverTests/Scenes/Home/HomePresenterTests.swift +++ b/iOS/Layover/LayoverTests/Scenes/Home/HomePresenterTests.swift @@ -68,6 +68,10 @@ final class HomePresenterTests: XCTestCase { } + func displayMorePosts(with viewModel: Layover.HomeModels.FetchPosts.ViewModel) { + + } + } // MARK: - Tests @@ -76,25 +80,35 @@ final class HomePresenterTests: XCTestCase { // arrange let spy = HomeDisplayLogicSpy() sut.viewController = spy - let response = Models.FetchPosts.Response(posts: [Seeds.Posts.post1]) + let response = Models.FetchPosts.Response(cursor: Seeds.PostsPage.cursor1, + posts: [Seeds.PostsPage.post1]) // act sut.presentPosts(with: response) // assert - XCTAssertTrue(spy.displayPostsCalled, "presentPosts는 displayPosts를 실행하지 못했다.") - XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts.count, 1, "presentPosts는 올바른 갯수의 데이터를 전달하지 못했다.") - XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].tags, Seeds.Posts.post1.tag, "presentPosts는 올바른 데이터를 전달하지 못했다.") - XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].title, Seeds.Posts.post1.board.title, "presentPosts는 올바른 데이터를 전달하지 못했다.") - XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].thumbnailImageURL, Seeds.Posts.post1.board.thumbnailImageURL, "presentPosts는 올바른 데이터를 전달하지 못했다.") - XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].videoURL, Seeds.Posts.post1.board.videoURL, "presentPosts는 올바른 데이터를 전달하지 못했다.") + XCTAssertTrue(spy.displayPostsCalled, + "presentPosts는 displayPosts를 실행하지 못했다.") + XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts.count, + 1, + "presentPosts는 올바른 갯수의 데이터를 전달하지 못했다.") + XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].tags, + Seeds.PostsPage.post1.tag, + "presentPosts는 올바른 데이터를 전달하지 못했다.") + XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].title, Seeds.PostsPage.post1.board.title, + "presentPosts는 올바른 데이터를 전달하지 못했다.") + XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].thumbnailImageURL, Seeds.PostsPage.post1.board.thumbnailImageURL, + "presentPosts는 올바른 데이터를 전달하지 못했다.") + XCTAssertEqual(spy.displayPostsReceivedViewModel.displayedPosts[0].videoURL, Seeds.PostsPage.post1.board.videoURL, + "presentPosts는 올바른 데이터를 전달하지 못했다.") } func test_presentPosts는_데이터의_썸네일_이미지_URL이_nil인_경우_뷰에게_해당_데이터를_전달하지_않는다() { // arrange let spy = HomeDisplayLogicSpy() sut.viewController = spy - let response = Models.FetchPosts.Response(posts: [Seeds.Posts.thumbnailImageNilPost]) + let response = Models.FetchPosts.Response(cursor: 400, + posts: [Seeds.Posts.thumbnailImageNilPost]) // act sut.presentPosts(with: response) @@ -108,7 +122,8 @@ final class HomePresenterTests: XCTestCase { // arrange let spy = HomeDisplayLogicSpy() sut.viewController = spy - let response = Models.FetchPosts.Response(posts: [Seeds.Posts.videoURLNilPost]) + let response = Models.FetchPosts.Response(cursor: 400, + posts: [Seeds.Posts.videoURLNilPost]) // act sut.presentPosts(with: response) diff --git a/iOS/Layover/LayoverTests/Scenes/Home/HomeWorkerTests.swift b/iOS/Layover/LayoverTests/Scenes/Home/HomeWorkerTests.swift index d0dd1017..1a316c0f 100644 --- a/iOS/Layover/LayoverTests/Scenes/Home/HomeWorkerTests.swift +++ b/iOS/Layover/LayoverTests/Scenes/Home/HomeWorkerTests.swift @@ -39,7 +39,7 @@ final class HomeWorkerTests: XCTestCase { func test_fetchPost는_성공적으로_데이터를_받아오면_Post배열을_리턴한다() async throws { // arrange - guard let mockFileLocation = Bundle(for: type(of: self)).url(forResource: "PostList", withExtension: "json"), + guard let mockFileLocation = Bundle(for: type(of: self)).url(forResource: "PostsPage", withExtension: "json"), let mockData = try? Data(contentsOf: mockFileLocation) else { XCTFail("Mock json 파일 로드 실패.") return @@ -55,24 +55,24 @@ final class HomeWorkerTests: XCTestCase { var result: [Post]? // act - result = await sut.fetchPosts() + result = await sut.fetchPosts()?.posts // assert XCTAssertNotNil(result) XCTAssertEqual(result?.count, 1, "fetchPost가 성공적으로 데이터를 받아와서 올바른 데이터 갯수를 리턴하지 못했다.") - XCTAssertEqual(result![0].tag, Seeds.Posts.post1.tag, "fetchPost가 성공적으로 데이터를 받아와서 올바른 tag를 리턴하지 못했다.") - XCTAssertEqual(result![0].board.thumbnailImageURL, Seeds.Posts.post1.board.thumbnailImageURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.identifier, Seeds.Posts.post1.board.identifier, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.title, Seeds.Posts.post1.board.title, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.description, Seeds.Posts.post1.board.description, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.videoURL, Seeds.Posts.post1.board.videoURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.latitude, Seeds.Posts.post1.board.latitude, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.longitude, Seeds.Posts.post1.board.longitude, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].board.status, Seeds.Posts.post1.board.status, "fetchPost가 성공적으로 데이터를 받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].member.identifier, Seeds.Posts.post1.member.identifier, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].member.username, Seeds.Posts.post1.member.username, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].member.introduce, Seeds.Posts.post1.member.introduce, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") - XCTAssertEqual(result![0].member.profileImageURL, Seeds.Posts.post1.member.profileImageURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].tag, Seeds.PostsPage.post1.tag, "fetchPost가 성공적으로 데이터를 받아와서 올바른 tag를 리턴하지 못했다.") + XCTAssertEqual(result![0].board.thumbnailImageURL, Seeds.PostsPage.post1.board.thumbnailImageURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.identifier, Seeds.PostsPage.post1.board.identifier, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.title, Seeds.PostsPage.post1.board.title, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.description, Seeds.PostsPage.post1.board.description, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.videoURL, Seeds.PostsPage.post1.board.videoURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.latitude, Seeds.PostsPage.post1.board.latitude, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.longitude, Seeds.PostsPage.post1.board.longitude, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].board.status, Seeds.PostsPage.post1.board.status, "fetchPost가 성공적으로 데이터를 받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].member.identifier, Seeds.PostsPage.post1.member.identifier, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].member.username, Seeds.PostsPage.post1.member.username, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].member.introduce, Seeds.PostsPage.post1.member.introduce, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") + XCTAssertEqual(result![0].member.profileImageURL, Seeds.PostsPage.post1.member.profileImageURL, "fetchPost가 성공적으로 데이터를_받아와서 Post배열을 리턴하지 못했다.") } func test_fetchPost는_데이터를_받아오지_못하면_nil을_리턴한다() async { @@ -87,7 +87,7 @@ final class HomeWorkerTests: XCTestCase { var result: [Post]? // act - result = await sut.fetchPosts() + result = await sut.fetchPosts()?.posts // assert XCTAssertNil(result) diff --git a/iOS/Layover/LayoverTests/Scenes/Profile/ProfileInteractorTests.swift b/iOS/Layover/LayoverTests/Scenes/Profile/ProfileInteractorTests.swift index aee566ce..37201290 100644 --- a/iOS/Layover/LayoverTests/Scenes/Profile/ProfileInteractorTests.swift +++ b/iOS/Layover/LayoverTests/Scenes/Profile/ProfileInteractorTests.swift @@ -78,11 +78,9 @@ final class ProfileInteractorTests: XCTestCase { XCTAssertTrue(presentationLogicSpy.presentProfileCalled, "fetchProfile을 호출해서 presentProfile을 호출하지 못했다") XCTAssertEqual(presentationLogicSpy.presentProfileResponse.displayedPosts.count, 1, "presentProfileResponse에는 fetchProfile의 결과 갯수가 올바르게 담기지 못했다.") XCTAssertEqual(presentationLogicSpy.presentProfileResponse.displayedPosts[0].id, Seeds.Posts.post1.board.identifier, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") - XCTAssertEqual(presentationLogicSpy.presentProfileResponse.displayedPosts[0].thumbnailImageData, Seeds.sampleImageData, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") XCTAssertEqual(presentationLogicSpy.presentProfileResponse.displayedPosts[0].status, Seeds.Posts.post1.board.status, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") XCTAssertEqual(presentationLogicSpy.presentProfileResponse.userProfile.username, Seeds.Members.getMember1.username, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") XCTAssertEqual(presentationLogicSpy.presentProfileResponse.userProfile.introduce, Seeds.Members.getMember1.introduce, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") - XCTAssertEqual(presentationLogicSpy.presentProfileResponse.userProfile.profileImageData, Seeds.sampleImageData, "presentProfileResponse에는 fetchProfile의 결과가 올바르게 담기지 못했다.") } func test_fetchMorePosts을_호출하면_presenter의_presentMorePosts을_호출하고_presentMorePostsResponse를_전달한다() async { @@ -97,7 +95,6 @@ final class ProfileInteractorTests: XCTestCase { XCTAssertTrue(presentationLogicSpy.presentMorePostsCalled, "fetchMorePosts을 호출해서 presentMorePosts을 호출하지 못했다") XCTAssertEqual(presentationLogicSpy.presentMorePostsResponse.displayedPosts.count, 1, "fetchMorePosts의 결과 갯수가 올바르게 담기지 못했다") XCTAssertEqual(presentationLogicSpy.presentMorePostsResponse.displayedPosts[0].id, Seeds.Posts.post1.board.identifier, "presentMorePostsResponse에는 fetchMorePosts의 결과가 올바르게 담기지 못했다") - XCTAssertEqual(presentationLogicSpy.presentMorePostsResponse.displayedPosts[0].thumbnailImageData, Seeds.sampleImageData, "presentMorePostsResponse에는 fetchMorePosts의 결과가 올바르게 담기지 못했다") XCTAssertEqual(presentationLogicSpy.presentMorePostsResponse.displayedPosts[0].status, Seeds.Posts.post1.board.status, "presentMorePostsResponse에는 fetchMorePosts의 결과가 올바르게 담기지 못했다") } diff --git a/iOS/Layover/LayoverTests/Scenes/Profile/ProfilePresenterTests.swift b/iOS/Layover/LayoverTests/Scenes/Profile/ProfilePresenterTests.swift index a7224e7e..2e110bb5 100644 --- a/iOS/Layover/LayoverTests/Scenes/Profile/ProfilePresenterTests.swift +++ b/iOS/Layover/LayoverTests/Scenes/Profile/ProfilePresenterTests.swift @@ -69,10 +69,10 @@ final class ProfilePresenterTests: XCTestCase { sut.viewController = spy let response = Models.FetchProfile.Response(userProfile: ProfileModels.Profile(username: Seeds.Members.getMember1.username, introduce: Seeds.Members.getMember1.introduce, - profileImageData: Seeds.sampleImageData), + profileImageURL: Seeds.Members.getMember1.profileImageURL), displayedPosts: [.init(id: Seeds.Posts.post1.board.identifier, - thumbnailImageData: Seeds.sampleImageData, - status: Seeds.Posts.post1.board.status)]) + thumbnailImageData: Seeds.Members.getMember1.profileImageURL, + status: Seeds.Posts.post1.board.status)]) // act sut.presentProfile(with: response) @@ -80,11 +80,11 @@ final class ProfilePresenterTests: XCTestCase { XCTAssertTrue(spy.displayProfileDidCalled, "presentProfile은 displayProfile을 호출하지 못했다") XCTAssertEqual(spy.displayProfileViewModel.userProfile.username, Seeds.Members.getMember1.username, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayProfileViewModel.userProfile.introduce, Seeds.Members.getMember1.introduce, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") - XCTAssertEqual(spy.displayProfileViewModel.userProfile.profileImageData, Seeds.sampleImageData, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") + XCTAssertEqual(spy.displayProfileViewModel.userProfile.profileImageURL, Seeds.Members.getMember1.profileImageURL, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayProfileViewModel.displayedPosts.count, 1, "presentProfile은 올바른 데이터 갯수를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayProfileViewModel.displayedPosts[0].id, Seeds.Posts.post1.board.identifier, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayProfileViewModel.displayedPosts[0].status, Seeds.Posts.post1.board.status, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") - XCTAssertEqual(spy.displayProfileViewModel.displayedPosts[0].thumbnailImageData, Seeds.sampleImageData, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") + XCTAssertEqual(spy.displayProfileViewModel.displayedPosts[0].thumbnailImageData, Seeds.Members.getMember1.profileImageURL, "presentProfile은 올바른 데이터를 뷰에 전달하지 못했다") } func test_presentMorePosts을_호출하면_displayMorePosts를_호출하고_올바른_데이터를_전달한다() { @@ -94,8 +94,8 @@ final class ProfilePresenterTests: XCTestCase { // act let response = Models.FetchMorePosts.Response(displayedPosts: [.init(id: Seeds.Posts.post1.board.identifier, - thumbnailImageData: Seeds.sampleImageData, - status: Seeds.Posts.post1.board.status)]) + thumbnailImageData: Seeds.Members.getMember1.profileImageURL, + status: Seeds.Posts.post1.board.status)]) sut.presentMorePosts(with: response) // assert @@ -103,7 +103,7 @@ final class ProfilePresenterTests: XCTestCase { XCTAssertEqual(spy.displayMorePostsViewModel.displayedPosts.count, 1, "presentMorePosts은 올바른 데이터 갯수를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayMorePostsViewModel.displayedPosts[0].id, Seeds.Posts.post1.board.identifier, "presentMorePosts은 올바른 데이터를 뷰에 전달하지 못했다") XCTAssertEqual(spy.displayMorePostsViewModel.displayedPosts[0].status, Seeds.Posts.post1.board.status, "presentMorePosts은 올바른 데이터를 뷰에 전달하지 못했다") - XCTAssertEqual(spy.displayMorePostsViewModel.displayedPosts[0].thumbnailImageData, Seeds.sampleImageData, "presentMorePosts은 올바른 데이터를 뷰에 전달하지 못했다") + XCTAssertEqual(spy.displayMorePostsViewModel.displayedPosts[0].thumbnailImageData, Seeds.Members.getMember1.profileImageURL, "presentMorePosts은 올바른 데이터를 뷰에 전달하지 못했다") } func test_presentPostDetail을_호출하면_routeToPostDetail을_호출한다() { diff --git a/iOS/Layover/LayoverTests/Seeds.swift b/iOS/Layover/LayoverTests/Seeds.swift index b9553424..0a092be0 100644 --- a/iOS/Layover/LayoverTests/Seeds.swift +++ b/iOS/Layover/LayoverTests/Seeds.swift @@ -12,6 +12,23 @@ import Foundation class Seeds { static let sampleImageData = try? Data(contentsOf: Bundle(for: Seeds.self).url(forResource: "sample", withExtension: "jpeg")!) + struct PostsPage { + static let cursor1 = 32 + static let post1 = Post(member: Member(identifier: 221, + username: "hwani", + introduce: "Hi, my name is hwani", + profileImageURL: URL(string: "https://layover-profile-image.kr.obj...")), + board: Board(identifier: 1, + title: "붓산 광안리", + description: "날씨가 정말 좋았따이", + thumbnailImageURL: URL(string: "https://layover-video-thumbnail.kr.obj..."), + videoURL: URL(string: "https://qc66zhsq1708.edge.naverncp.com/hls/fMG98Ec1UirV-awtm4qKJyhanmRFlPLZbTs_/layover-station/sv_AVC_HD, SD_1Pass_30fps.mp4/index.m3u8"), + latitude: 37.0532156213, + longitude: 37.0532156213, + status: .complete), + tag: ["tag1", "tag2"]) + } + struct Posts { // PostList.json에 정의된 데이터 static let post1 = Post(member: Member(identifier: 1,