From aa45f76312a77a9859e46d3139dff6ed0b7a5c63 Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:35:09 +0300 Subject: [PATCH 1/7] Create lint.yml --- .github/workflows/lint.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml new file mode 100644 index 0000000..fb11b2d --- /dev/null +++ b/.github/workflows/lint.yml @@ -0,0 +1,11 @@ +# Lint.yml +name: Lint +on: pull_request + +jobs: + Lint: + runs-on: macos-latest + steps: + - uses: actions/checkout@v4 + - name: SwiftFormat + run: swiftformat --lint . --reporter github-actions-log From 8f4d1580612717de0185d48b7de56ade8fdb2dbd Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:35:50 +0300 Subject: [PATCH 2/7] Init API tests. --- Tests/MBAsyncNetworkingTests/APITests.swift | 31 +++++++++++++++++++ .../MBAsyncNetworkingTests.swift | 6 ---- 2 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 Tests/MBAsyncNetworkingTests/APITests.swift delete mode 100644 Tests/MBAsyncNetworkingTests/MBAsyncNetworkingTests.swift diff --git a/Tests/MBAsyncNetworkingTests/APITests.swift b/Tests/MBAsyncNetworkingTests/APITests.swift new file mode 100644 index 0000000..4b808fa --- /dev/null +++ b/Tests/MBAsyncNetworkingTests/APITests.swift @@ -0,0 +1,31 @@ +import Foundation +import Testing +@testable import MBAsyncNetworking + +@MainActor struct APITests { + init() { + UserSession.initialize(with: NetworkingStorage()) + } + + @Test func apiTest() async throws { + // Write your test here and use APIs like `#expect(...)` to check expected conditions. + let request: Data = try await TestAPI.google.fetch() + #expect(request.count > 0) + } + + enum TestAPI: AsyncNetworkable { + case google + case amazon + func request() async -> URLRequest { + switch self { + case .google: await getRequest(queryItems: [:], url: URL(forceString: "https://google.com")) + case .amazon: await getRequest(queryItems: [:], url: URL(forceString: "https://amazon.com")) + } + } + } + + struct NetworkingStorage: NetworkingStorable { + var refreshToken: String? = UUID().uuidString + var accessToken: String? = UUID().uuidString + } +} diff --git a/Tests/MBAsyncNetworkingTests/MBAsyncNetworkingTests.swift b/Tests/MBAsyncNetworkingTests/MBAsyncNetworkingTests.swift deleted file mode 100644 index 1b256f5..0000000 --- a/Tests/MBAsyncNetworkingTests/MBAsyncNetworkingTests.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Testing -@testable import MBAsyncNetworking - -@Test func example() async throws { - // Write your test here and use APIs like `#expect(...)` to check expected conditions. -} From 8aace6ef3678201ddd0da4ad10f1c6a305e2d8aa Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:35:58 +0300 Subject: [PATCH 3/7] Update APITests.swift From bdf20a53a599433043c50386721bf4576a08e547 Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:36:15 +0300 Subject: [PATCH 4/7] Update AsyncNetworkable+URLRequest.swift --- Sources/MBAsyncNetworking/AsyncNetworkable+URLRequest.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/MBAsyncNetworking/AsyncNetworkable+URLRequest.swift b/Sources/MBAsyncNetworking/AsyncNetworkable+URLRequest.swift index 84372f2..9b4ee01 100644 --- a/Sources/MBAsyncNetworking/AsyncNetworkable+URLRequest.swift +++ b/Sources/MBAsyncNetworking/AsyncNetworkable+URLRequest.swift @@ -59,7 +59,7 @@ public extension AsyncNetworkable { request.httpBody = getBody(body) return request } - + /// Creates a URLRequest with a JSON body and query parameters /// - Parameters: /// - queryItems: Dictionary of query parameters to be added to the URL From 63122397ff5e1d251fc29fcd678c8842bba40284 Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:38:39 +0300 Subject: [PATCH 5/7] Refactor NetworkingStorage and add MultipleSceneTests Moved NetworkingStorage to its own file and removed it from APITests.swift. Added MultipleSceneTests to test user session initialization with NetworkingStorage. --- Tests/MBAsyncNetworkingTests/APITests.swift | 5 ----- .../MultipleSceneTests.swift | 15 +++++++++++++++ .../NetworkingStorage.swift | 14 ++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift create mode 100644 Tests/MBAsyncNetworkingTests/NetworkingStorage.swift diff --git a/Tests/MBAsyncNetworkingTests/APITests.swift b/Tests/MBAsyncNetworkingTests/APITests.swift index 4b808fa..19cc3fe 100644 --- a/Tests/MBAsyncNetworkingTests/APITests.swift +++ b/Tests/MBAsyncNetworkingTests/APITests.swift @@ -23,9 +23,4 @@ import Testing } } } - - struct NetworkingStorage: NetworkingStorable { - var refreshToken: String? = UUID().uuidString - var accessToken: String? = UUID().uuidString - } } diff --git a/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift b/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift new file mode 100644 index 0000000..60fffb9 --- /dev/null +++ b/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift @@ -0,0 +1,15 @@ +// +// MultipleSceneTests.swift +// MBAsyncNetworking +// +// Created by Raşid Ramazanov on 5.08.2025. +// + +import Testing +@testable import MBAsyncNetworking + +@MainActor struct MultipleSceneTests { + init() { + UserSession.initialize(with: NetworkingStorage()) + } +} diff --git a/Tests/MBAsyncNetworkingTests/NetworkingStorage.swift b/Tests/MBAsyncNetworkingTests/NetworkingStorage.swift new file mode 100644 index 0000000..021a79f --- /dev/null +++ b/Tests/MBAsyncNetworkingTests/NetworkingStorage.swift @@ -0,0 +1,14 @@ +// +// NetworkingStorage.swift +// MBAsyncNetworking +// +// Created by Raşid Ramazanov on 5.08.2025. +// + +import Foundation +@testable import MBAsyncNetworking + +struct NetworkingStorage: NetworkingStorable { + var refreshToken: String? = UUID().uuidString + var accessToken: String? = UUID().uuidString +} From e2fe7350f3f32faaa75b5f6938a03f8881dd9af9 Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Tue, 5 Aug 2025 15:56:11 +0300 Subject: [PATCH 6/7] Add XViewController and interactor fetch test Introduces XViewController, XInteractor, XPresenter, and related protocols for testing async network fetch logic. Adds a test case to verify interactor fetch behavior and uses a spy to assert correct presentation logic. --- .../MultipleSceneTests.swift | 102 ++++++++++++++++++ 1 file changed, 102 insertions(+) diff --git a/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift b/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift index 60fffb9..2eeaba8 100644 --- a/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift +++ b/Tests/MBAsyncNetworkingTests/MultipleSceneTests.swift @@ -5,11 +5,113 @@ // Created by Raşid Ramazanov on 5.08.2025. // +import Foundation import Testing @testable import MBAsyncNetworking @MainActor struct MultipleSceneTests { + var sut: XViewController! init() { UserSession.initialize(with: NetworkingStorage()) } + + @Test mutating func interactorFetch() async { + let presentationLogic = XPresentationLogicSpy() + sut = XViewController(presentationLogic: presentationLogic) + await sut.interactor.fetch() + #expect(presentationLogic.content != nil) + #expect(presentationLogic.error == nil) + } + + final class XPresentationLogicSpy: XPresentationLogic { + var viewController: (any MultipleSceneTests.XDisplayLogic)? + var content: Data? + var error: Error? + func present(data: Data) { + content = data + } + + func present(error: any Error) { + self.error = error + } + } + + final class XViewController: XDisplayLogic { + let interactor: XInteractor + var content: Data? + var errorMessage: String? + init() { + let presenter = XPresenter() + interactor = XInteractor(presenter: presenter) + presenter.viewController = self + } + + init(presentationLogic: XPresentationLogic) { + interactor = XInteractor(presenter: presentationLogic) + interactor.presenter.viewController = self + } + + func viewDidLoad() { + Task { + await interactor.fetch() + } + } + + func displayContent(_ data: Data) { + content = data + } + + func displayError(_ message: String) { + errorMessage = message + } + } + + protocol XDisplayLogic { + func displayContent(_ data: Data) + func displayError(_ message: String) + } + + final class XInteractor { + var presenter: XPresentationLogic + init(presenter: XPresentationLogic) { + self.presenter = presenter + } + + func fetch() async { + do { + let response: Data = try await TestAPI.google.fetch() + presenter.present(data: response) + } catch { + presenter.present(error: error) + } + } + } + + final class XPresenter: XPresentationLogic { + var viewController: XDisplayLogic? + func present(data: Data) { + viewController?.displayContent(data) + } + + func present(error: Error) { + viewController?.displayError(error.localizedDescription) + } + } + + protocol XPresentationLogic { + var viewController: XDisplayLogic? { get set } + func present(data: Data) + func present(error: Error) + } + + enum TestAPI: AsyncNetworkable { + case google + case amazon + func request() async -> URLRequest { + switch self { + case .google: await getRequest(queryItems: [:], url: URL(forceString: "https://google.com")) + case .amazon: await getRequest(queryItems: [:], url: URL(forceString: "https://amazon.com")) + } + } + } } From 088aa970072e1f182b4f470fe00e49af2983563e Mon Sep 17 00:00:00 2001 From: Rashid Ramazanov Date: Fri, 30 Jan 2026 16:58:37 +0300 Subject: [PATCH 7/7] Update AsyncNetworkable+Data.swift --- Sources/MBAsyncNetworking/AsyncNetworkable+Data.swift | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Sources/MBAsyncNetworking/AsyncNetworkable+Data.swift b/Sources/MBAsyncNetworking/AsyncNetworkable+Data.swift index 94577bb..b65b30e 100644 --- a/Sources/MBAsyncNetworking/AsyncNetworkable+Data.swift +++ b/Sources/MBAsyncNetworking/AsyncNetworkable+Data.swift @@ -47,8 +47,7 @@ public extension AsyncNetworkable { return data as! T // swiftlint:enable force_cast } - let response = try decoder.decode(T.self, from: data) - return response + return try decoder.decode(T.self, from: data) } catch { let error = NSError( domain: "",