From b6f1ab68fe2aac5366b0bf8d0621eb49176923c0 Mon Sep 17 00:00:00 2001 From: Adam Young Date: Mon, 16 Sep 2024 15:46:38 +0100 Subject: [PATCH 1/5] WIP --- .../APIRequestQueryItemNameTests.swift | 81 +++++++++++-------- .../Domain/APIClient/MockAPIClient.swift | 2 +- Tests/TMDbTests/TestUtils/Tags.swift | 3 + 3 files changed, 53 insertions(+), 33 deletions(-) diff --git a/Tests/TMDbTests/Domain/APIClient/APIRequestQueryItemNameTests.swift b/Tests/TMDbTests/Domain/APIClient/APIRequestQueryItemNameTests.swift index 8c7cae6f..970a6b20 100644 --- a/Tests/TMDbTests/Domain/APIClient/APIRequestQueryItemNameTests.swift +++ b/Tests/TMDbTests/Domain/APIClient/APIRequestQueryItemNameTests.swift @@ -17,69 +17,86 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -final class APIRequestQueryItemNameTests: XCTestCase { +@Suite(.tags(.apiClient, .domain)) +struct APIRequestQueryItemNameTests { - func testPageName() { - XCTAssertEqual(APIRequestQueryItem.Name.page, "page") + @Test("pageName") + func pageQueryItemName() { + #expect(APIRequestQueryItem.Name.page == "page") } - func testSortByName() { - XCTAssertEqual(APIRequestQueryItem.Name.sortBy, "sort_by") + @Test("sortBy") + func sortByQueryItemName() { + #expect(APIRequestQueryItem.Name.sortBy == "sort_by") } - func testWithPeopleName() { - XCTAssertEqual(APIRequestQueryItem.Name.withPeople, "with_people") + @Test("withPeople") + func withPeopleQueryItemName() { + #expect(APIRequestQueryItem.Name.withPeople == "with_people") } - func testWatchRegionName() { - XCTAssertEqual(APIRequestQueryItem.Name.watchRegion, "watch_region") + @Test("watchRegion") + func watchRegionQueryItemName() { + #expect(APIRequestQueryItem.Name.watchRegion == "watch_region") } - func testIncludeImageLanguageName() { - XCTAssertEqual(APIRequestQueryItem.Name.includeImageLanguage, "include_image_language") + @Test("includeImageLanguage") + func includeImageLanguageQueryItemName() { + #expect(APIRequestQueryItem.Name.includeImageLanguage == "include_image_language") } - func testIncludeVideoLanguageName() { - XCTAssertEqual(APIRequestQueryItem.Name.includeVideoLanguage, "include_video_language") + @Test("includeVideoLanguage") + func includeVideoLanguageQueryItemName() { + #expect(APIRequestQueryItem.Name.includeVideoLanguage == "include_video_language") } - func testIncludeAdultName() { - XCTAssertEqual(APIRequestQueryItem.Name.includeAdult, "include_adult") + @Test("includeAdult") + func includeAdultQueryItemName() { + #expect(APIRequestQueryItem.Name.includeAdult == "include_adult") } - func testQueryName() { - XCTAssertEqual(APIRequestQueryItem.Name.query, "query") + @Test("query") + func queryQueryItemName() { + #expect(APIRequestQueryItem.Name.query == "query") } - func testYearName() { - XCTAssertEqual(APIRequestQueryItem.Name.year, "year") + @Test("year") + func yearQueryItemName() { + #expect(APIRequestQueryItem.Name.year == "year") } - func testPrimaryReleaseYearName() { - XCTAssertEqual(APIRequestQueryItem.Name.primaryReleaseYear, "primary_release_year") + @Test("primaryReleaseYear") + func primaryReleaseYearQueryItemName() { + #expect(APIRequestQueryItem.Name.primaryReleaseYear == "primary_release_year") } - func testFirstAirDateYearName() { - XCTAssertEqual(APIRequestQueryItem.Name.firstAirDateYear, "first_air_date_year") + @Test("firstAirDateYear") + func firstAirDateYearQueryItemName() { + #expect(APIRequestQueryItem.Name.firstAirDateYear == "first_air_date_year") } - func testSessionIDName() { - XCTAssertEqual(APIRequestQueryItem.Name.sessionID, "session_id") + @Test("sesionID") + func sessionIDQueryItemName() { + #expect(APIRequestQueryItem.Name.sessionID == "session_id") } - func testLanguageName() { - XCTAssertEqual(APIRequestQueryItem.Name.language, "language") + @Test("language") + func languageQueryItemName() { + #expect(APIRequestQueryItem.Name.language == "language") } - func testRegionName() { - XCTAssertEqual(APIRequestQueryItem.Name.region, "region") + @Test("region") + func regionQueryItemName() { + #expect(APIRequestQueryItem.Name.region == "region") } - func testAPIKeyName() { - XCTAssertEqual(APIRequestQueryItem.Name.apiKey, "api_key") + @Test("apiKey") + func apiKeyQueryItemName() { + #expect(APIRequestQueryItem.Name.apiKey == "api_key") } } diff --git a/Tests/TMDbTests/Domain/APIClient/MockAPIClient.swift b/Tests/TMDbTests/Domain/APIClient/MockAPIClient.swift index cd6f5890..08da0aa0 100644 --- a/Tests/TMDbTests/Domain/APIClient/MockAPIClient.swift +++ b/Tests/TMDbTests/Domain/APIClient/MockAPIClient.swift @@ -17,8 +17,8 @@ // limitations under the License. // +import Foundation @testable import TMDb -import XCTest final class MockAPIClient: APIClient, @unchecked Sendable { diff --git a/Tests/TMDbTests/TestUtils/Tags.swift b/Tests/TMDbTests/TestUtils/Tags.swift index f331ef3a..e75cab75 100644 --- a/Tests/TMDbTests/TestUtils/Tags.swift +++ b/Tests/TMDbTests/TestUtils/Tags.swift @@ -21,8 +21,11 @@ import Testing extension Tag { + @Tag static var domain: Self + @Tag static var models: Self @Tag static var services: Self + @Tag static var apiClient: Self @Tag static var decoding: Self @Tag static var requests: Self From 3e4b64a501d03bbab99d4be0105be56c97b61424 Mon Sep 17 00:00:00 2001 From: Adam Young Date: Mon, 16 Sep 2024 20:13:19 +0100 Subject: [PATCH 2/5] REFACTOR: Migrate Networking tests to Swift Testing --- .swiftlint.yml | 2 + Sources/TMDb/Networking/TMDbAPIError.swift | 63 ++++- .../HTTPClient/HTTPRequestMethodTests.swift | 21 +- .../HTTPClient/MockURLProtocol.swift | 3 - .../TMDbAuthJSONSerialiserTests.swift | 46 ++-- .../Serialisers/TMDbJSONSerialiserTests.swift | 46 ++-- .../Networking/TMDbAPIClientTests.swift | 78 +++--- .../TMDbAPIErrorHTTPStatusCodeTests.swift | 224 +++++++----------- Tests/TMDbTests/TestUtils/Tags.swift | 1 + 9 files changed, 230 insertions(+), 254 deletions(-) diff --git a/.swiftlint.yml b/.swiftlint.yml index 61aa87da..6b6f8d56 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -18,7 +18,9 @@ identifier_name: - id - job - key + - l - lhs + - r - rhs - tv - url diff --git a/Sources/TMDb/Networking/TMDbAPIError.swift b/Sources/TMDb/Networking/TMDbAPIError.swift index ec44b765..0befe3f4 100644 --- a/Sources/TMDb/Networking/TMDbAPIError.swift +++ b/Sources/TMDb/Networking/TMDbAPIError.swift @@ -22,7 +22,7 @@ import Foundation /// /// A model representing a TMDb API error. /// -enum TMDbAPIError: Error { +enum TMDbAPIError: Error, Equatable { /// /// Invalid URL. @@ -114,4 +114,65 @@ enum TMDbAPIError: Error { /// case unknown + static func == (lhs: TMDbAPIError, rhs: TMDbAPIError) -> Bool { + switch (lhs, rhs) { + case let (.invalidURL(l), .invalidURL(r)): + l == r + + case (.network, .network): + true + + case let (.badRequest(l), .badRequest(r)): + l == r + + case let (.unauthorised(l), .unauthorised(r)): + l == r + + case let (.forbidden(l), .forbidden(r)): + l == r + + case let (.notFound(l), .notFound(r)): + l == r + + case let (.methodNotAllowed(l), .methodNotAllowed(r)): + l == r + + case let (.notAcceptable(l), .notAcceptable(r)): + l == r + + case let (.unprocessableContent(l), .unprocessableContent(r)): + l == r + + case let (.tooManyRequests(l), .tooManyRequests(r)): + l == r + + case let (.internalServerError(l), .internalServerError(r)): + l == r + + case let (.notImplemented(l), .notImplemented(r)): + l == r + + case let (.badGateway(l), .badGateway(r)): + l == r + + case let (.serviceUnavailable(l), .serviceUnavailable(r)): + l == r + + case let (.gatewayTimeout(l), .gatewayTimeout(r)): + l == r + + case (.encode, .encode): + true + + case (.decode, .decode): + true + + case (.unknown, .unknown): + true + + default: + false + } + } + } diff --git a/Tests/TMDbTests/Networking/HTTPClient/HTTPRequestMethodTests.swift b/Tests/TMDbTests/Networking/HTTPClient/HTTPRequestMethodTests.swift index 04c2d98e..2c6925c6 100644 --- a/Tests/TMDbTests/Networking/HTTPClient/HTTPRequestMethodTests.swift +++ b/Tests/TMDbTests/Networking/HTTPClient/HTTPRequestMethodTests.swift @@ -17,21 +17,26 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -final class HTTPRequestMethodTests: XCTestCase { +@Suite(.tags(.networking)) +struct HTTPRequestMethodTests { - func testGetMethod() { - XCTAssertEqual(HTTPRequest.Method.get.rawValue, "GET") + @Test("get method should be equal to \"GET\"") + func getMethod() { + #expect(HTTPRequest.Method.get.rawValue == "GET") } - func testPostMethod() { - XCTAssertEqual(HTTPRequest.Method.post.rawValue, "POST") + @Test("post method should be equal to \"POST\"") + func postMethod() { + #expect(HTTPRequest.Method.post.rawValue == "POST") } - func testDeleteMethod() { - XCTAssertEqual(HTTPRequest.Method.delete.rawValue, "DELETE") + @Test("delete method should be equal to \"DELETE\"") + func deleteMethod() { + #expect(HTTPRequest.Method.delete.rawValue == "DELETE") } } diff --git a/Tests/TMDbTests/Networking/HTTPClient/MockURLProtocol.swift b/Tests/TMDbTests/Networking/HTTPClient/MockURLProtocol.swift index 5da8cde6..ec3d96eb 100644 --- a/Tests/TMDbTests/Networking/HTTPClient/MockURLProtocol.swift +++ b/Tests/TMDbTests/Networking/HTTPClient/MockURLProtocol.swift @@ -18,9 +18,6 @@ // import Foundation -#if canImport(FoundationNetworking) - @preconcurrency import FoundationNetworking -#endif final class MockURLProtocol: URLProtocol, @unchecked Sendable { diff --git a/Tests/TMDbTests/Networking/Serialisers/TMDbAuthJSONSerialiserTests.swift b/Tests/TMDbTests/Networking/Serialisers/TMDbAuthJSONSerialiserTests.swift index a0b010df..3830743c 100644 --- a/Tests/TMDbTests/Networking/Serialisers/TMDbAuthJSONSerialiserTests.swift +++ b/Tests/TMDbTests/Networking/Serialisers/TMDbAuthJSONSerialiserTests.swift @@ -17,65 +17,55 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -final class TMDbAuthSerialiserTests: XCTestCase { +@Suite(.tags(.networking)) +struct TMDbAuthSerialiserTests { var serialiser: Serialiser! - override func setUp() { - super.setUp() - serialiser = TMDbAuthJSONSerialiser() + init() { + self.serialiser = TMDbAuthJSONSerialiser() } - override func tearDown() { - serialiser = nil - super.tearDown() - } - - func testDecodeWhenDataCannotBeDecodedThrowsDecodeError() async throws { + @Test("decode when data cannot be decoded throws decode error") + func decodeWhenDataCannotBeDecodedThrowsDecodeError() async throws { let data = Data("aaa".utf8) - var error: Error? - do { + await #expect(throws: Error.self) { _ = try await serialiser.decode(MockObject.self, from: data) - } catch let decodeError { - error = decodeError } - - XCTAssertNotNil(error) } - func testDecodeWhenDataCanBeDecodedReturnsDecodedObject() async throws { + @Test("decode when data can be decoded returns decoded object") + func decodeWhenDataCanBeDecodedReturnsDecodedObject() async throws { let expectedResult = MockObject() let data = expectedResult.data let result = try await serialiser.decode(MockObject.self, from: data) - XCTAssertEqual(result, expectedResult) + #expect(result == expectedResult) } - func testEncodeWhenDataCannotBeEncodedThrowsEncodeError() async throws { + @Test("encode when data cannot be encoded throws encode error") + func encodeWhenDataCannotBeEncodedThrowsEncodeError() async throws { let data = Data() - var error: Error? - do { + await #expect(throws: Error.self) { _ = try await serialiser.decode(MockObject.self, from: data) - } catch let decodeError { - error = decodeError } - - XCTAssertNotNil(error) } - func testEncodeWhenDataCanBeEncodedReturnsData() async throws { + @Test("encode when data can be encoded returns data") + func encodeWhenDataCanBeEncodedReturnsData() async throws { let value = MockObject() let expectedResult = value.data let result = try await serialiser.encode(value) - XCTAssertEqual(result, expectedResult) + #expect(result == expectedResult) } } diff --git a/Tests/TMDbTests/Networking/Serialisers/TMDbJSONSerialiserTests.swift b/Tests/TMDbTests/Networking/Serialisers/TMDbJSONSerialiserTests.swift index 0d81e520..67911321 100644 --- a/Tests/TMDbTests/Networking/Serialisers/TMDbJSONSerialiserTests.swift +++ b/Tests/TMDbTests/Networking/Serialisers/TMDbJSONSerialiserTests.swift @@ -17,65 +17,55 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -final class TMDbJSONSerialiserTests: XCTestCase { +@Suite(.tags(.networking)) +struct TMDbJSONSerialiserTests { var serialiser: Serialiser! - override func setUp() { - super.setUp() - serialiser = TMDbJSONSerialiser() + init() { + self.serialiser = TMDbJSONSerialiser() } - override func tearDown() { - serialiser = nil - super.tearDown() - } - - func testDecodeWhenDataCannotBeDecodedThrowsDecodeError() async throws { + @Test("decode when data cannot be decoded throws decode error") + func decodeWhenDataCannotBeDecodedThrowsDecodeError() async throws { let data = Data("aaa".utf8) - var error: Error? - do { + await #expect(throws: Error.self) { _ = try await serialiser.decode(MockObject.self, from: data) - } catch let decodeError { - error = decodeError } - - XCTAssertNotNil(error) } - func testDecodeWhenDataCanBeDecodedReturnsDecodedObject() async throws { + @Test("decode when data can be decoded returns decoded object") + func decodeWhenDataCanBeDecodedReturnsDecodedObject() async throws { let expectedResult = MockObject() let data = expectedResult.data let result = try await serialiser.decode(MockObject.self, from: data) - XCTAssertEqual(result, expectedResult) + #expect(result == expectedResult) } - func testEncodeWhenDataCannotBeEncodedThrowsEncodeError() async throws { + @Test("enconde when data cannot be encoded throws encode error") + func encodeWhenDataCannotBeEncodedThrowsEncodeError() async throws { let data = Data() - var error: Error? - do { + await #expect(throws: Error.self) { _ = try await serialiser.decode(MockObject.self, from: data) - } catch let decodeError { - error = decodeError } - - XCTAssertNotNil(error) } - func testEncodeWhenDataCanBeEncodedReturnsData() async throws { + @Test("encode when data can be encoded returns data") + func encodeWhenDataCanBeEncodedReturnsData() async throws { let value = MockObject() let expectedResult = value.data let result = try await serialiser.encode(value) - XCTAssertEqual(result, expectedResult) + #expect(result == expectedResult) } } diff --git a/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift b/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift index db562dd7..c9a1dc0e 100644 --- a/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift +++ b/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift @@ -17,13 +17,12 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -#if canImport(FoundationNetworking) - import FoundationNetworking -#endif -final class TMDbAPIClientTests: XCTestCase { +@Suite(.tags(.networking)) +struct TMDbAPIClientTests { var apiClient: TMDbAPIClient! var apiKey: String! @@ -31,15 +30,14 @@ final class TMDbAPIClientTests: XCTestCase { var serialiser: TMDbJSONSerialiser! var httpClient: HTTPMockClient! - override func setUp() async throws { - try await super.setUp() - apiKey = "abc123" - baseURL = try XCTUnwrap(URL(string: "https://some.domain.com/path")) - serialiser = TMDbJSONSerialiser() + init() async throws { + self.apiKey = "abc123" + self.baseURL = try #require(URL(string: "https://some.domain.com/path")) + self.serialiser = TMDbJSONSerialiser() let configuration = URLSessionConfiguration.default configuration.protocolClasses = [MockURLProtocol.self] - httpClient = await HTTPMockClient() - apiClient = TMDbAPIClient( + self.httpClient = await HTTPMockClient() + self.apiClient = TMDbAPIClient( apiKey: apiKey, baseURL: baseURL, serialiser: serialiser, @@ -47,73 +45,59 @@ final class TMDbAPIClientTests: XCTestCase { ) } - override func tearDown() async throws { - apiClient = nil - httpClient = nil - serialiser = nil - baseURL = nil - apiKey = nil - try await super.tearDown() - } - + @Test("perform when invalid path throws error") @MainActor - func testPerformWhenInvalidPathThrowsError() async throws { - let stubRequest = APIStubRequest(path: "") + func performWhenInvalidPathThrowsError() async throws { + let path = "" + let stubRequest = APIStubRequest(path: path) httpClient.result = .success(HTTPResponse()) - var error: TMDbAPIError? - do { + await #expect(throws: TMDbAPIError.invalidURL(path)) { _ = try await apiClient.perform(stubRequest) - } catch let err { - error = err as? TMDbAPIError - } - - switch error { - case let .invalidURL(path): - XCTAssertEqual(path, "") - - default: - XCTFail("Unexpected error") } } + @Test("perform has correct URL") @MainActor - func testPerformHasCorrectURL() async throws { + func performHasCorrectURL() async throws { let stubRequest = APIStubRequest(path: "/endpoint") - let expectedURL = try XCTUnwrap(URL(string: "https://some.domain.com/path/endpoint")) + let expectedURL = try #require(URL(string: "https://some.domain.com/path/endpoint")) httpClient.result = .success(HTTPResponse()) _ = try? await apiClient.perform(stubRequest) - let request = try XCTUnwrap(httpClient.lastRequest) + let request = try #require(httpClient.lastRequest) - XCTAssertTrue(request.url.absoluteString.starts(with: expectedURL.absoluteString)) + #expect(request.url.absoluteString.starts(with: expectedURL.absoluteString)) } + @Test("perform when GET method") @MainActor - func testPerformWhenGetMethod() async throws { + func performWhenGetMethod() async throws { let stubRequest = APIStubRequest(path: "/endpoint", method: .get) httpClient.result = .success(HTTPResponse()) _ = try? await apiClient.perform(stubRequest) - let request = try XCTUnwrap(httpClient.lastRequest) + let request = try #require(httpClient.lastRequest) - XCTAssertEqual(request.method, .get) + #expect(request.method == .get) } + @Test("perform when POST method") @MainActor - func testPerformWhenPostMethod() async throws { + func performWhenPostMethod() async throws { let stubRequest = APIStubRequest(path: "/endpoint", method: .post) httpClient.result = .success(HTTPResponse()) _ = try? await apiClient.perform(stubRequest) - let request = try XCTUnwrap(httpClient.lastRequest) + let request = try #require(httpClient.lastRequest) - XCTAssertEqual(request.method, .post) + #expect(request.method == .post) } + @Test("perfom when DELETE method") @MainActor func testPerformWhenDeleteMethod() async throws { let stubRequest = APIStubRequest(path: "/endpoint", method: .delete) @@ -121,9 +105,9 @@ final class TMDbAPIClientTests: XCTestCase { _ = try? await apiClient.perform(stubRequest) - let request = try XCTUnwrap(httpClient.lastRequest) + let request = try #require(httpClient.lastRequest) - XCTAssertEqual(request.method, .delete) + #expect(request.method == .delete) } } diff --git a/Tests/TMDbTests/Networking/TMDbAPIErrorHTTPStatusCodeTests.swift b/Tests/TMDbTests/Networking/TMDbAPIErrorHTTPStatusCodeTests.swift index bda47f03..d49c63a5 100644 --- a/Tests/TMDbTests/Networking/TMDbAPIErrorHTTPStatusCodeTests.swift +++ b/Tests/TMDbTests/Networking/TMDbAPIErrorHTTPStatusCodeTests.swift @@ -17,218 +17,164 @@ // limitations under the License. // +import Foundation +import Testing @testable import TMDb -import XCTest -final class TMDbAPIErrorHTTPStatusCodeTests: XCTestCase { +@Suite(.tags(.networking)) +struct TMDbAPIErrorHTTPStatusCodeTests { - func testBadRequest() { + @Test("Bad request") + func badRequest() { let statusCode = 400 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.badRequest(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .badRequest(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } + @Test("Unauthorised") func testUnauthorised() { let statusCode = 401 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.unauthorised(message) - switch error { - case let .unauthorised(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testForbidden() { + @Test("Forbidden") + func forbidden() { let statusCode = 403 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.forbidden(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .forbidden(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testNotFound() { + @Test("Not found") + func notFound() { let statusCode = 404 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.notFound(message) - switch error { - case let .notFound(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testMethodNotAllowed() { + @Test("Method not allowed") + func methodNotAllowed() { let statusCode = 405 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.methodNotAllowed(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .methodNotAllowed(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testNotAcceptable() { + @Test("Not acceptable") + func notAcceptable() { let statusCode = 406 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.notAcceptable(message) - switch error { - case let .notAcceptable(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testUnprocessableContent() { + @Test("Unprocessable content") + func unprocessableContent() { let statusCode = 422 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.unprocessableContent(message) - switch error { - case let .unprocessableContent(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testTooManyRequests() { + @Test("Too many requests") + func tooManyRequests() { let statusCode = 429 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.tooManyRequests(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .tooManyRequests(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testInternalServerError() { + @Test("Internal server error") + func internalServerError() { let statusCode = 500 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.internalServerError(message) - switch error { - case let .internalServerError(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testNotImplemented() { + @Test("Not implemented") + func notImplemented() { let statusCode = 501 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.notImplemented(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .notImplemented(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testBadGateway() { + @Test("Bad gateway") + func badGateway() { let statusCode = 502 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.badGateway(message) - switch error { - case let .badGateway(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testServiceUnavailable() { + @Test("Service unavailable") + func serviceUnavailable() { let statusCode = 503 - let expectedMessage = "Some error message" + let message = "Some error message" + let expectedError = TMDbAPIError.serviceUnavailable(message) - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - switch error { - case let .serviceUnavailable(message): - XCTAssertEqual(message, expectedMessage) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testGatewayTimeout() { + @Test("Gateway timeout") + func gatewayTimeout() { let statusCode = 504 - let expectedMessage = "Some error message" - - let error = TMDbAPIError(statusCode: statusCode, message: expectedMessage) + let message = "Some error message" + let expectedError = TMDbAPIError.gatewayTimeout(message) - switch error { - case let .gatewayTimeout(message): - XCTAssertEqual(message, expectedMessage) + let error = TMDbAPIError(statusCode: statusCode, message: message) - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } - func testUnknown() { + @Test("Unknown") + func unknown() { let statusCode = 999 + let expectedError = TMDbAPIError.unknown let error = TMDbAPIError(statusCode: statusCode, message: nil) - switch error { - case .unknown: - XCTAssertTrue(true) - - default: - XCTFail("Error does not match") - } + #expect(error == expectedError) } } diff --git a/Tests/TMDbTests/TestUtils/Tags.swift b/Tests/TMDbTests/TestUtils/Tags.swift index e75cab75..3f6693de 100644 --- a/Tests/TMDbTests/TestUtils/Tags.swift +++ b/Tests/TMDbTests/TestUtils/Tags.swift @@ -22,6 +22,7 @@ import Testing extension Tag { @Tag static var domain: Self + @Tag static var networking: Self @Tag static var models: Self @Tag static var services: Self From 644c431557ffcb16cb307e65ea1477aa451008cb Mon Sep 17 00:00:00 2001 From: Adam Young Date: Mon, 16 Sep 2024 20:38:03 +0100 Subject: [PATCH 3/5] Fix concurrency issue --- Makefile | 4 ++++ Package.swift | 2 +- Tests/TMDbTests/Networking/TMDbAPIClientTests.swift | 7 ++++++- 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 135d2621..8e8505d2 100644 --- a/Makefile +++ b/Makefile @@ -33,6 +33,10 @@ lint-markdown: build: swift build -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete +.PHONY: build-tests +build-tests: + swift build --build-tests -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + .PHONY: build-linux build-linux: docker run --rm -v "$${PWD}:/workspace" -w /workspace $(SWIFT_CONTAINER_IMAGE) /bin/bash -cl "swift build -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete" diff --git a/Package.swift b/Package.swift index b04d2160..f80e6d42 100644 --- a/Package.swift +++ b/Package.swift @@ -1,4 +1,4 @@ -// swift-tools-version:5.9 +// swift-tools-version:6.0 // The swift-tools-version declares the minimum version of Swift required to build this package. import class Foundation.ProcessInfo diff --git a/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift b/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift index c9a1dc0e..2288b7d7 100644 --- a/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift +++ b/Tests/TMDbTests/Networking/TMDbAPIClientTests.swift @@ -52,9 +52,14 @@ struct TMDbAPIClientTests { let stubRequest = APIStubRequest(path: path) httpClient.result = .success(HTTPResponse()) - await #expect(throws: TMDbAPIError.invalidURL(path)) { + var error: TMDbAPIError? + do { _ = try await apiClient.perform(stubRequest) + } catch let err { + error = err as? TMDbAPIError } + + #expect(error == .invalidURL(path)) } @Test("perform has correct URL") From 0204219c89b58e89f1cf53cf458d8ba4df9d76f6 Mon Sep 17 00:00:00 2001 From: Adam Young Date: Mon, 16 Sep 2024 20:40:17 +0100 Subject: [PATCH 4/5] Update builds --- .github/workflows/ci.yml | 12 ++++++------ Makefile | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 423190b1..231af35c 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,10 +28,10 @@ jobs: uses: actions/checkout@v4 - name: Build - run: swift build --build-tests -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + run: swift build --build-tests -Xswiftc -warnings-as-errors - name: Test - run: swift test --filter TMDbTests --enable-code-coverage -Xswiftc -strict-concurrency=complete + run: swift test --filter TMDbTests --enable-code-coverage - name: Prepare Code Coverage run: | @@ -48,7 +48,7 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - name: Build for Release - run: swift build -c release -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + run: swift build -c release -Xswiftc -warnings-as-errors build-and-test-platforms: name: Build and Test (${{ matrix.name }}) @@ -84,10 +84,10 @@ jobs: # uses: actions/checkout@v4 # - name: Build - # run: swift build --build-tests -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + # run: swift build --build-tests -Xswiftc -warnings-as-errors # - name: Test - # run: swift test --skip-build --filter TMDbTests -Xswiftc -strict-concurrency=complete + # run: swift test --skip-build --filter TMDbTests # - name: Build for Release - # run: swift build -c release -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + # run: swift build -c release -Xswiftc -warnings-as-errors diff --git a/Makefile b/Makefile index 8e8505d2..534c757a 100644 --- a/Makefile +++ b/Makefile @@ -31,23 +31,23 @@ lint-markdown: .PHONY: build build: - swift build -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + swift build -Xswiftc -warnings-as-errors .PHONY: build-tests build-tests: - swift build --build-tests -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + swift build --build-tests -Xswiftc -warnings-as-errors .PHONY: build-linux build-linux: - docker run --rm -v "$${PWD}:/workspace" -w /workspace $(SWIFT_CONTAINER_IMAGE) /bin/bash -cl "swift build -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete" + docker run --rm -v "$${PWD}:/workspace" -w /workspace $(SWIFT_CONTAINER_IMAGE) /bin/bash -cl "swift build -Xswiftc -warnings-as-errors .PHONY: build-release build-release: - swift build -c release -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete + swift build -c release -Xswiftc -warnings-as-errors .PHONY: build-linux-release build-linux-release: - docker run --rm -v "$${PWD}:/workspace" -w /workspace $(SWIFT_CONTAINER_IMAGE) /bin/bash -cl "swift build -c release -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete" + docker run --rm -v "$${PWD}:/workspace" -w /workspace $(SWIFT_CONTAINER_IMAGE) /bin/bash -cl "swift build -c release -Xswiftc -warnings-as-errors" .PHONY: build-docs build-docs: @@ -69,8 +69,8 @@ generate-docs: .PHONY: test test: - swift build --build-tests -Xswiftc -warnings-as-errors -Xswiftc -strict-concurrency=complete - swift test --skip-build --filter $(TEST_TARGET) -Xswiftc -strict-concurrency=complete + swift build --build-tests -Xswiftc -warnings-as-errors + swift test --skip-build --filter $(TEST_TARGET) .PHONY: test-ios test-ios: @@ -98,8 +98,8 @@ test-linux: .PHONY: integration-test integration-test: .check-env-vars - swift build --build-tests -Xswiftc -strict-concurrency=complete - swift test --skip-build --filter $(INTEGRATION_TEST_TARGET) -Xswiftc -strict-concurrency=complete + swift build --build-tests + swift test --skip-build --filter $(INTEGRATION_TEST_TARGET) .PHONY: ci ci: .check-env-vars lint lint-markdown test test-ios test-watchos test-tvos test-visionos integration-test build-release build-docs From 33080db61e891b80cdc28d3fe45539311862709c Mon Sep 17 00:00:00 2001 From: Adam Young Date: Mon, 16 Sep 2024 20:42:18 +0100 Subject: [PATCH 5/5] Update builds --- .github/workflows/documentation.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 80aed632..c54d70c2 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -26,7 +26,7 @@ jobs: build: name: Build runs-on: ubuntu-latest - container: swift:5.9.2-jammy + container: swiftlang/swift:nightly-6.0-jammy steps: - name: Checkout uses: actions/checkout@v4