From 3d923982b1bd170ccfdb17e56b1a0d07b8db7d4e Mon Sep 17 00:00:00 2001 From: Javier Cicchelli Date: Fri, 12 Sep 2025 00:13:58 +0000 Subject: [PATCH] Improvements on the `AmiiboService` service type initialization (#12) This PR addresses the issue #10 as described in the *Possible Solution* section in that issue. Reviewed-on: https://repo.rock-n-code.com/rock-n-code/amiibo-service/pulls/12 Co-authored-by: Javier Cicchelli Co-committed-by: Javier Cicchelli --- .../Public/Clients/AmiiboLiveClient.swift | 4 +- .../Public/Clients/AmiiboMockClient.swift | 263 ---- .../Protocols/AmiiboClient.swift} | 2 +- .../Public/Services/AmiiboService.swift | 11 +- .../Services/AmiiboServiceLiveTests.swift | 1110 ++++++++++++++++- .../Types/Clients/AmiiboMockClient.swift | 217 ++++ .../Types/Extensions/Tag+Customs.swift | 17 +- 7 files changed, 1341 insertions(+), 283 deletions(-) delete mode 100644 Sources/AmiiboService/Public/Clients/AmiiboMockClient.swift rename Sources/AmiiboService/{Internal/Protocols/APIClient.swift => Public/Protocols/AmiiboClient.swift} (99%) create mode 100644 Tests/AmiiboService/Types/Clients/AmiiboMockClient.swift rename Sources/AmiiboService/Public/Enumerations/AmiiboClient.swift => Tests/AmiiboService/Types/Extensions/Tag+Customs.swift (50%) diff --git a/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift b/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift index 1cc938e..01ff620 100644 --- a/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift +++ b/Sources/AmiiboService/Public/Clients/AmiiboLiveClient.swift @@ -36,10 +36,10 @@ public struct AmiiboLiveClient { } -// MARK: - APIClient +// MARK: - AmiiboClient // TODO: Remove the documentation from the functions inside the following extension as the `--enable-inherited-docs` flag when generating DocC documentation is not working as intended (?). -extension AmiiboLiveClient: APIClient { +extension AmiiboLiveClient: AmiiboClient { // MARK: Functions diff --git a/Sources/AmiiboService/Public/Clients/AmiiboMockClient.swift b/Sources/AmiiboService/Public/Clients/AmiiboMockClient.swift deleted file mode 100644 index 789e77f..0000000 --- a/Sources/AmiiboService/Public/Clients/AmiiboMockClient.swift +++ /dev/null @@ -1,263 +0,0 @@ -//===----------------------------------------------------------------------=== -// -// This source file is part of the AmiiboService open source project -// -// Copyright (c) 2024-2025 Röck+Cöde VoF. and the AmiiboAPI project authors -// Licensed under the EUPL 1.2 or later. -// -// See LICENSE for license information -// See CONTRIBUTORS for the list of AmiiboAPI project authors -// -//===----------------------------------------------------------------------=== - -import Foundation - -/// A type that implements a mock client, for testing purposes. -public struct AmiiboMockClient { - - // MARK: Properties - - /// A list of amiibo items to return, if any. - private let amiibos: [Amiibo]? - - /// A list of amiibo series to return, if any. - private let amiiboSeries: [AmiiboSeries]? - - /// A list of amiibo types to return, if any. - private let amiiboTypes: [AmiiboType]? - - /// An error to throw, if any. - private let error: AmiiboServiceError? - - /// A list of game characters to return, if any. - private let gameCharacters: [GameCharacter]? - - /// A list of game series to return, if any. - private let gameSeries: [GameSeries]? - - /// A last updated date to return, if any. - private let lastUpdated: Date? - - // MARK: Initializers - - /// Initializes this client. - /// - Parameters: - /// - amiibos: A list of amiibo items to return, if any. - /// - amiiboSeries: A list of amiibo series to return, if any. - /// - amiiboTypes: A list of amiibo types to return, if any. - /// - gameCharacters: A list of game characters to return, if any. - /// - gameSeries: A list of game series to return, if any. - /// - lastUpdated: A last updated date to return, if any. - /// - error: An error to throw, if any. - public init( - amiibos: [Amiibo]? = nil, - amiiboSeries: [AmiiboSeries]? = nil, - amiiboTypes: [AmiiboType]? = nil, - gameCharacters: [GameCharacter]? = nil, - gameSeries: [GameSeries]? = nil, - lastUpdated: Date? = nil, - error: AmiiboServiceError? = nil - ) { - self.amiibos = amiibos - self.amiiboSeries = amiiboSeries - self.amiiboTypes = amiiboTypes - self.error = error - self.gameCharacters = gameCharacters - self.gameSeries = gameSeries - self.lastUpdated = lastUpdated - } - -} - -// MARK: - APIClient -// TODO: Remove the documentation from the functions inside the following extension as the `--enable-inherited-docs` flag when generating DocC documentation is not working as intended (?). - -extension AmiiboMockClient: APIClient { - - // MARK: Functions - -#if swift(>=6.0) - /// Gets a list of amiibo items based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo items. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiibos(by filter: AmiiboFilter) async throws(AmiiboServiceError) -> [Amiibo] { - try throwErrorIfExists() - - guard let amiibos else { - throw AmiiboServiceError.notFound - } - - return amiibos - } - - /// Gets a list of amiibo series based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo series. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws(AmiiboServiceError) -> [AmiiboSeries] { - try throwErrorIfExists() - - guard let amiiboSeries else { - throw AmiiboServiceError.notFound - } - - return amiiboSeries - } - - /// Gets a list of amiibo types based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo types. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws(AmiiboServiceError) -> [AmiiboType] { - try throwErrorIfExists() - - guard let amiiboTypes else { - throw AmiiboServiceError.notFound - } - - return amiiboTypes - } - - /// Gets a list of game characters based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered game characters. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getGameCharacters(by filter: GameCharacterFilter) async throws(AmiiboServiceError) -> [GameCharacter] { - try throwErrorIfExists() - - guard let gameCharacters else { - throw AmiiboServiceError.notFound - } - - return gameCharacters - } - - /// Gets a list of game series based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered game series. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getGameSeries(by filter: GameSeriesFilter) async throws(AmiiboServiceError) -> [GameSeries] { - try throwErrorIfExists() - - guard let gameSeries else { - throw AmiiboServiceError.notFound - } - - return gameSeries - } - - /// Gets the date when the data was last updated. - /// - Returns: A last updated date. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getLastUpdated() async throws(AmiiboServiceError) -> Date { - try throwErrorIfExists() - - guard let lastUpdated else { - throw AmiiboServiceError.notFound - } - - return lastUpdated - } -#else - /// Gets a list of amiibo items based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo items. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiibos(by filter: AmiiboFilter) async throws -> [Amiibo] { - try throwErrorIfExists() - - guard let amiibos else { - throw AmiiboServiceError.notFound - } - - return amiibos - } - - /// Gets a list of amiibo series based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo series. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws -> [AmiiboSeries] { - try throwErrorIfExists() - - guard let amiiboSeries else { - throw AmiiboServiceError.notFound - } - - return amiiboSeries - } - - /// Gets a list of amiibo types based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered amiibo types. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws -> [AmiiboType] { - try throwErrorIfExists() - - guard let amiiboTypes else { - throw AmiiboServiceError.notFound - } - - return amiiboTypes - } - - /// Gets a list of game characters based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered game characters. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getGameCharacters(by filter: GameCharacterFilter) async throws -> [GameCharacter] { - try throwErrorIfExists() - - guard let gameCharacters else { - throw AmiiboServiceError.notFound - } - - return gameCharacters - } - - /// Gets a list of game series based on a given filter. - /// - Parameter filter: A filter to remove unwanted items from the result. - /// - Returns: A list of filtered game series. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getGameSeries(by filter: GameSeriesFilter) async throws -> [GameSeries] { - try throwErrorIfExists() - - guard let gameSeries else { - throw AmiiboServiceError.notFound - } - - return gameSeries - } - - /// Gets the date when the data was last updated. - /// - Returns: A last updated date. - /// - Throws: An ``AmiiboServiceError`` error in case some issue is encountered while generating the result. - public func getLastUpdated() async throws -> Date { - try throwErrorIfExists() - - guard let lastUpdated else { - throw AmiiboServiceError.notFound - } - - return lastUpdated - } -#endif - -} - -// MARK: - Helpers - -private extension AmiiboMockClient { - - // MARK: Functions - - /// Throws an error if it has been provided, - /// - Throws: An ``AmiiboServiceError`` error in case an error has been provided. - func throwErrorIfExists() throws(AmiiboServiceError) { - if let error { - throw error - } - } - -} diff --git a/Sources/AmiiboService/Internal/Protocols/APIClient.swift b/Sources/AmiiboService/Public/Protocols/AmiiboClient.swift similarity index 99% rename from Sources/AmiiboService/Internal/Protocols/APIClient.swift rename to Sources/AmiiboService/Public/Protocols/AmiiboClient.swift index 49e40da..288b755 100644 --- a/Sources/AmiiboService/Internal/Protocols/APIClient.swift +++ b/Sources/AmiiboService/Public/Protocols/AmiiboClient.swift @@ -13,7 +13,7 @@ import Foundation /// A protocol that defines API clients containing all available endpoints to interact with. -protocol APIClient { +public protocol AmiiboClient { // MARK: Functions diff --git a/Sources/AmiiboService/Public/Services/AmiiboService.swift b/Sources/AmiiboService/Public/Services/AmiiboService.swift index fdb947f..51e9bd1 100644 --- a/Sources/AmiiboService/Public/Services/AmiiboService.swift +++ b/Sources/AmiiboService/Public/Services/AmiiboService.swift @@ -18,17 +18,14 @@ public struct AmiiboService { // MARK: Properties /// A client to interact with the endpoints. - private let client: any APIClient + private let client: any AmiiboClient // MARK: Initializers /// Initializes this service with a specific client type. - /// - Parameter client: A representation of a client to use to interact with the endpoints. - public init(_ client: AmiiboClient) { - self.client = switch client { - case let .mock(mockClient): mockClient - case let .live(liveClient): liveClient - } + /// - Parameter client: A client to use to interact with the endpoints. + public init(client: some AmiiboClient = AmiiboLiveClient()) { + self.client = client } // MARK: Functions diff --git a/Tests/AmiiboService/Tests/Public/Services/AmiiboServiceLiveTests.swift b/Tests/AmiiboService/Tests/Public/Services/AmiiboServiceLiveTests.swift index 908c379..9120977 100644 --- a/Tests/AmiiboService/Tests/Public/Services/AmiiboServiceLiveTests.swift +++ b/Tests/AmiiboService/Tests/Public/Services/AmiiboServiceLiveTests.swift @@ -14,7 +14,7 @@ import AmiiboService import Foundation import Testing -@Suite("Live service") +@Suite("Amiibo Service", .tags(.live)) struct AmiiboServiceLiveTests { // MARK: Properties @@ -24,11 +24,12 @@ struct AmiiboServiceLiveTests { // MARK: Initializers init() { - self.service = .init(.live()) + self.service = .init() } // MARK: Functions tests +#if swift(>=6.2) @Test func `get Amiibo items`() async throws { // GIVEN @@ -1131,5 +1132,1110 @@ struct AmiiboServiceLiveTests { #expect(dateComponents.month == 7) #expect(dateComponents.day == 18) } +#else + @Test("Get Amiibo items") + func getAmiibos() async throws { + // GIVEN + // WHEN + let amiibos = try await service.getAmiibos() + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + #expect(amiibos.first?.identifier == "0000000000000002") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.identifier == "3f000000042e0002") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by an existing identifier") + func getAmiibos_byExistingIdentifier() async throws { + // GIVEN + let identifier = "0000000000000002" + + // WHEN + let amiibos = try await service.getAmiibos(.init(identifier: identifier)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 1) + #expect(amiibos.first?.identifier == identifier) + #expect(amiibos.first?.platform == nil) + } + + @Test("Get Amiibo items by a non-existing identifier") + func getAmiibos_byNonExistingIdentifier() async throws { + // GIVEN + let identifier = "0000000000000000" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.decoding) { + try await service.getAmiibos(.init(identifier: identifier)) + } + } + + @Test("Get Amiibo items by an incomplete identifier") + func getAmiibos_byIncompleteIdentifier() async throws { + // GIVEN + let identifier = "0000000" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.decoding) { + try await service.getAmiibos(.init(identifier: identifier)) + } + } + + @Test("Get Amiibo items by an empty identifier") + func getAmiibos_byEmptyIdentifier() async throws { + // GIVEN + let identifier = "" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiibos(.init(identifier: identifier)) + } + } + + @Test("Get Amiibo items by an existing name") + func getAmiibos_byExistingName() async throws { + // GIVEN + let name = "zelda" + + // WHEN + let amiibos = try await service.getAmiibos(.init(name: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 5) + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.platform == nil) + + let nameFirst = try #require(amiibos.first?.name.lowercased()) + let nameLast = try #require(amiibos.last?.name.lowercased()) + + #expect(nameFirst.contains(name)) + #expect(nameLast.contains(name)) + } + + @Test("Get Amiibo items by a non-existing name") + func getAmiibos_byNonExistingName() async throws { + // GIVEN + let name = "Something" + + // WHEN + let amiibos = try await service.getAmiibos(.init(name: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an incomplete name") + func getAmiibos_byIncompleteName() async throws { + // GIVEN + let name = "zel" + + // WHEN + let amiibos = try await service.getAmiibos(.init(name: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 7) + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.platform == nil) + + let nameFirst = try #require(amiibos.first?.name.lowercased()) + let nameLast = try #require(amiibos.last?.name.lowercased()) + + #expect(nameFirst.contains(name)) + #expect(nameLast.contains(name)) + } + + @Test("Get Amiibo items by an empty name") + func getAmiibos_byEmptyName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(name: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an existing type key") + func getAmiibos_byExistingTypeKey() async throws { + // GIVEN + let key = "0x00" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 235) + #expect(amiibos.first?.type == "Figure") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.type == "Figure") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by an existing type name") + func getAmiibos_byExistingTypeName() async throws { + // GIVEN + let name = "figure" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 235) + #expect(amiibos.first?.type == "Figure") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.type == "Figure") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by a non-existing type key") + func getAmiibos_byNonExistingTypeKey() async throws { + // GIVEN + let key = "0x0f" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: key)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by a non-existing type name") + func getAmiibos_byNonExistingTypeName() async throws { + // GIVEN + let name = "something" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an incomplete type key") + func getAmiibos_byIncompleteTypeKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiibos(.init(type: key)) + } + } + + @Test("Get Amiibo items by an incomplete type name") + func getAmiibos_byIncompleteTypeName() async throws { + // GIVEN + let name = "fig" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an empty type key") + func getAmiibos_byEmptyTypeKey() async throws { + // GIVEN + let key = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: key)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an empty type name") + func getAmiibos_byEmptyTypeName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(type: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an existing series key") + func getAmiibos_byExistingSeriesKey() async throws { + // GIVEN + let key = "0x00" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 96) + #expect(amiibos.first?.series == "Super Smash Bros.") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.series == "Super Smash Bros.") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by an existing series name") + func getAmiibos_byExistingSeriesName() async throws { + // GIVEN + let name = "Legend Of Zelda" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 26) + #expect(amiibos.first?.series == name) + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.series == name) + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by a non-existing series key") + func getAmiibos_byNonExistingSeriesKey() async throws { + // GIVEN + let key = "0xf9" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: key)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by a non-existing series name") + func getAmiibos_byNonExistingSeriesName() async throws { + // GIVEN + let name = "something" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an incomplete series key") + func getAmiibos_byIncompleteSeriesKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiibos(.init(series: key)) + } + } + + @Test("Get Amiibo items by an incomplete series name") + func getAmiibos_byIncompleteSeriesName() async throws { + // GIVEN + let name = "fig" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 25) + } + + @Test("Get Amiibo items by an empty series key") + func getAmiibos_byEmptySeriesKey() async throws { + // GIVEN + let key = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an empty series name") + func getAmiibos_byEmptySeriesName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(series: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an existing game character key") + func getAmiibos_byExistingGameCharacterKey() async throws { + // GIVEN + let key = "0x00" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 11) + #expect(amiibos.first?.gameCharacter == "Mario") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.gameCharacter == "Mario") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by an existing game character name") + func getAmiibos_byExistingGameCharacterName() async throws { + // GIVEN + let name = "Zelda" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 6) + #expect(amiibos.first?.gameCharacter == name) + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.gameCharacter == name) + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by a non-existing game character key") + func getAmiibos_byNonExistingGameCharacterKey() async throws { + // GIVEN + let key = "0xf9" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: key)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by a non-existing game character name") + func getAmiibos_byNonExistingGameCharacterName() async throws { + // GIVEN + let name = "something" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an incomplete game character key") + func getAmiibos_byIncompleteGameCharacterKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiibos(.init(gameCharacter: key)) + } + } + + @Test("Get Amiibo items by an incomplete game character name") + func getAmiibos_byIncompleteGameCharacterName() async throws { + // GIVEN + let name = "fig" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an empty game character key") + func getAmiibos_byEmptyGameCharacterKey() async throws { + // GIVEN + let key = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an empty game character name") + func getAmiibos_byEmptyGameCharacterName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameCharacter: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an existing game series key") + func getAmiibos_byExistingGameSeriesKey() async throws { + // GIVEN + let key = "0x00" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 45) + #expect(amiibos.first?.gameSeries == "Super Mario") + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.gameSeries == "Super Mario") + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by an existing game series name") + func getAmiibos_byExistingGameSeriesName() async throws { + // GIVEN + let name = "The Legend of Zelda" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 32) + #expect(amiibos.first?.gameSeries == name) + #expect(amiibos.first?.platform == nil) + #expect(amiibos.last?.gameSeries == name) + #expect(amiibos.last?.platform == nil) + } + + @Test("Get Amiibo items by a non-existing game series key") + func getAmiibos_byNonExistingGameSeriesKey() async throws { + // GIVEN + let key = "0xf9" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: key)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by a non-existing game series name") + func getAmiibos_byNonExistingGameSeriesName() async throws { + // GIVEN + let name = "something" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: name)) + + // THEN + #expect(amiibos.isEmpty) + } + + @Test("Get Amiibo items by an incomplete game series key") + func getAmiibos_byIncompleteGameSeriesKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiibos(.init(gameSeries: key)) + } + } + + @Test("Get Amiibo items by an incomplete game series name") + func getAmiibos_byIncompleteGameSeriesName() async throws { + // GIVEN + let name = "Super" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 143) + } + + @Test("Get Amiibo items by an empty game series key") + func getAmiibos_byEmptyGameSeriesKey() async throws { + // GIVEN + let key = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: key)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items by an empty game series name") + func getAmiibos_byEmptyGameSeriesName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiibos = try await service.getAmiibos(.init(gameSeries: name)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + } + + @Test("Get Amiibo items with games data") + func getAmiibos_withGamesData() async throws { + // GIVEN + // WHEN + let amiibos = try await service.getAmiibos(.init(showGames: true)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + #expect(amiibos.first?.platform != nil) + #expect(amiibos.first?.platform?.switch.isEmpty == false) + #expect(amiibos.first?.platform?.switch.first?.usages == nil) + #expect(amiibos.first?.platform?.threeDS.isEmpty == false) + #expect(amiibos.first?.platform?.threeDS.first?.usages == nil) + #expect(amiibos.first?.platform?.wiiU.isEmpty == false) + #expect(amiibos.first?.platform?.wiiU.first?.usages == nil) + #expect(amiibos.last?.platform != nil) + } + + @Test("Get Amiibo items with games and usages data") + func getAmiibos_withGamesAndUsagesData() async throws { + // GIVEN + // WHEN + let amiibos = try await service.getAmiibos(.init(showUsage: true)) + + // THEN + #expect(!amiibos.isEmpty) + #expect(amiibos.count == 885) + #expect(amiibos.first?.platform != nil) + #expect(amiibos.first?.platform?.switch.isEmpty == false) + #expect(amiibos.first?.platform?.switch.first?.usages?.isEmpty == false) + #expect(amiibos.first?.platform?.threeDS.isEmpty == false) + #expect(amiibos.first?.platform?.threeDS.first?.usages?.isEmpty == false) + #expect(amiibos.first?.platform?.wiiU.isEmpty == false) + #expect(amiibos.first?.platform?.wiiU.first?.usages?.isEmpty == false) + #expect(amiibos.last?.platform != nil) + } + + @Test("Get Amiibo series") + func getAmiiboSeries() async throws { + // GIVEN + // WHEN + let amiiboSeries = try await service.getAmiiboSeries() + + // THEN + #expect(!amiiboSeries.isEmpty) + #expect(amiiboSeries.count == 28) + #expect(amiiboSeries.first?.key == "0x00") + #expect(amiiboSeries.last?.key == "0xff") + } + + @Test("Get Amiibo series by an existing key") + func getAmiiboSeries_byExistingKey() async throws { + // GIVEN + let key = "0x01" + + // WHEN + let amiiboSeries = try await service.getAmiiboSeries(.init(key: key)) + + // THEN + #expect(!amiiboSeries.isEmpty) + #expect(amiiboSeries.count == 1) + #expect(amiiboSeries.first?.key == key) + } + + @Test("Get Amiibo series by a non-existing key") + func getAmiiboSeries_byNonExistingKey() async throws { + // GIVEN + let key = "0xf9" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getAmiiboSeries(.init(key: key)) + } + } + + @Test("Get Amiibo series by an incomplete key") + func getAmiiboSeries_byIncompleteKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiiboSeries(.init(key: key)) + } + } + + @Test("Get Amiibo series by an empty key") + func getAmiiboSeries_byEmptyKey() async throws { + // GIVEN + let key = "" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiiboSeries(.init(key: key)) + } + } + + @Test("Get Amiibo series by an existing name") + func getAmiiboSeries_byExistingName() async throws { + // GIVEN + let name = "Legend Of Zelda" + + // WHEN + let amiiboSeries = try await service.getAmiiboSeries(.init(name: name)) + + // THEN + #expect(!amiiboSeries.isEmpty) + #expect(amiiboSeries.count == 1) + #expect(amiiboSeries.first?.name == name) + } + + @Test("Get Amiibo series by a non-existing name") + func getAmiiboSeries_byNonExistingName() async throws { + // GIVEN + let name = "Something" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getAmiiboSeries(.init(name: name)) + } + } + + @Test("Get Amiibo series by an incomplete name") + func getAmiiboSeries_byIncompleteName() async throws { + // GIVEN + let name = "Zelda" + + // WHEN + let amiiboSeries = try await service.getAmiiboSeries(.init(name: name)) + + // THEN + #expect(!amiiboSeries.isEmpty) + #expect(amiiboSeries.count == 1) + + let amiiboSeriesName = try #require(amiiboSeries.first) + + #expect(amiiboSeriesName.name.contains(name)) + } + + @Test("Get Amiibo series by an empty name") + func getAmiiboSeries_byEmptyName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiiboSeries = try await service.getAmiiboSeries(.init(name: name)) + + // THEN + #expect(!amiiboSeries.isEmpty) + #expect(amiiboSeries.count == 28) + #expect(amiiboSeries.first?.key == "0x00") + #expect(amiiboSeries.last?.key == "0xff") + } + + @Test("Get Amiibo types") + func getAmiiboTypes() async throws { + // GIVEN + // WHEN + let amiiboTypes = try await service.getAmiiboTypes() + + // THEN + #expect(!amiiboTypes.isEmpty) + #expect(amiiboTypes.count == 4) + #expect(amiiboTypes.first?.key == "0x00") + #expect(amiiboTypes.last?.key == "0x03") + } + + @Test("Get Amiibo types by an existing key") + func getAmiiboTypes_byExistingKey() async throws { + // GIVEN + let key = "0x01" + + // WHEN + let amiiboTypes = try await service.getAmiiboTypes(.init(key: key)) + + // THEN + #expect(!amiiboTypes.isEmpty) + #expect(amiiboTypes.count == 1) + #expect(amiiboTypes.first?.key == key) + } + + @Test("Get Amiibo types by a non-existing key") + func getAmiiboTypes_byNonExistingKey() async throws { + // GIVEN + let key = "0x09" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getAmiiboTypes(.init(key: key)) + } + } + + @Test("Get Amiibo types by an incomplete key") + func getAmiiboTypes_byIncompleteKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiiboTypes(.init(key: key)) + } + } + + @Test("Get Amiibo types by an empty key") + func getAmiiboTypes_byEmptyKey() async throws { + // GIVEN + let key = "" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getAmiiboTypes(.init(key: key)) + } + } + + @Test("Get Amiibo types by an existing name") + func getAmiiboTypes_byExistingName() async throws { + // GIVEN + let name = "Card" + + // WHEN + let amiiboTypes = try await service.getAmiiboTypes(.init(name: name)) + + // THEN + #expect(!amiiboTypes.isEmpty) + #expect(amiiboTypes.count == 1) + #expect(amiiboTypes.first?.name == name) + } + + @Test("Get Amiibo types by a non-existing name") + func getAmiiboTypes_byNonExistingName() async throws { + // GIVEN + let name = "Something" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getAmiiboTypes(.init(name: name)) + } + } + + @Test("Get Amiibo types by an incomplete name") + func getAmiiboTypes_byIncompleteName() async throws { + // GIVEN + let name = "Ca" + + // WHEN + let amiiboTypes = try await service.getAmiiboTypes(.init(name: name)) + + // THEN + #expect(!amiiboTypes.isEmpty) + #expect(amiiboTypes.count == 1) + + let amiiboTypeName = try #require(amiiboTypes.first) + + #expect(amiiboTypeName.name.contains(name)) + } + + @Test("Get Amiibo types by an empty name") + func getAmiiboTypes_byEmptyName() async throws { + // GIVEN + let name = "" + + // WHEN + let amiiboTypes = try await service.getAmiiboTypes(.init(name: name)) + + // THEN + #expect(!amiiboTypes.isEmpty) + #expect(amiiboTypes.count == 4) + #expect(amiiboTypes.first?.key == "0x00") + #expect(amiiboTypes.last?.key == "0x03") + } + + @Test("Get game characters") + func getGameCharacters() async throws { + // GIVEN + // WHEN + let gameCharacters = try await service.getGameCharacters() + + // THEN + #expect(!gameCharacters.isEmpty) + #expect(gameCharacters.count == 668) + #expect(gameCharacters.first?.key == "0x0000") + #expect(gameCharacters.last?.key == "0x3f00") + } + + @Test("Get game characters by an existing key") + func getGameCharacters_byExistingKey() async throws { + // GIVEN + let key = "0x0001" + + // WHEN + let gameCharacters = try await service.getGameCharacters(.init(key: key)) + + // THEN + #expect(!gameCharacters.isEmpty) + #expect(gameCharacters.count == 1) + #expect(gameCharacters.first?.key == key) + } + + @Test("Get game characters by a non-existing key") + func getGameCharacters_byNonExistingKey() async throws { + // GIVEN + let key = "0xffff" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getGameCharacters(.init(key: key)) + } + } + + @Test("Get game characters by an incomplete key") + func getGameCharacters_byIncompleteKey() async throws { + // GIVEN + let key = "0x" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getGameCharacters(.init(key: key)) + } + } + + @Test("Get game characters by an empty key") + func getGameCharacters_byEmptyKey() async throws { + // GIVEN + let key = "" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getGameCharacters(.init(key: key)) + } + } + + @Test("Get game characters by an existing name") + func getGameCharacters_byExistingName() async throws { + // GIVEN + let name = "Zelda" + + // WHEN + let gameCharacters = try await service.getGameCharacters(.init(name: name)) + + // THEN + #expect(!gameCharacters.isEmpty) + #expect(gameCharacters.count == 1) + #expect(gameCharacters.first?.name == name) + } + + @Test("Get game characters by a non-existing name") + func getGameCharacters_byNonExistingName() async throws { + // GIVEN + let name = "Something" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getGameCharacters(.init(name: name)) + } + } + + @Test("Get game characters by an incomplete name") + func getGameCharacters_byIncompleteName() async throws { + // GIVEN + let name = "Zeld" + + // WHEN + let gameCharacters = try await service.getGameCharacters(.init(name: name)) + + // THEN + #expect(!gameCharacters.isEmpty) + #expect(gameCharacters.count == 1) + + let gameCharactersName = try #require(gameCharacters.first) + + #expect(gameCharactersName.name.contains(name)) + } + + @Test("Get game characters by an empty name") + func getGameCharacters_byEmptyName() async throws { + // GIVEN + let name = "" + + // WHEN + let gameCharacters = try await service.getGameCharacters(.init(name: name)) + + // THEN + #expect(!gameCharacters.isEmpty) + #expect(gameCharacters.count == 668) + #expect(gameCharacters.first?.key == "0x0000") + #expect(gameCharacters.last?.key == "0x3f00") + } + + @Test("Get game series") + func getGameSeries() async throws { + // GIVEN + // WHEN + let gameSeries = try await service.getGameSeries() + + // THEN + #expect(!gameSeries.isEmpty) + #expect(gameSeries.count == 117) + #expect(gameSeries.first?.key == "0x000") + #expect(gameSeries.last?.key == "0x3f0") + } + + @Test("Get game series by an existing key") + func getGameSeries_byExistingKey() async throws { + // GIVEN + let key = "0x001" + + // WHEN + let gameSeries = try await service.getGameSeries(.init(key: key)) + + // THEN + #expect(!gameSeries.isEmpty) + #expect(gameSeries.count == 1) + #expect(gameSeries.first?.key == key) + } + + @Test("Get game series by a non-existing key") + func getGameSeries_byNonExistingKey() async throws { + // GIVEN + let key = "0xffff" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getGameSeries(.init(key: key)) + } + } + + @Test("Get game series by an incomplete key") + func getGameSeries_byIncompleteKey() async throws { + // GIVEN + let key = "0x" + + // WHEN & THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getGameSeries(.init(key: key)) + } + } + + @Test("Get game series by an empty key") + func getGameSeries_byEmptyKey() async throws { + // GIVEN + let key = "" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.badRequest) { + try await service.getGameSeries(.init(key: key)) + } + } + + @Test("Get game series by an existing name") + func getGameSeries_byExistingName() async throws { + // GIVEN + let name = "Pikmin" + + // WHEN + let gameSeries = try await service.getGameSeries(.init(name: name)) + + // THEN + #expect(!gameSeries.isEmpty) + #expect(gameSeries.count == 1) + #expect(gameSeries.first?.name == name) + } + + @Test("Get game series by a non-existing name") + func getGameSeries_byNonExistingName() async throws { + // GIVEN + let name = "Something" + + // WHEN + // THEN + await #expect(throws: AmiiboServiceError.notFound) { + try await service.getGameSeries(.init(name: name)) + } + } + + @Test("Get game series by an incomplete name") + func getGameSeries_byIncompleteName() async throws { + // GIVEN + let name = "Pik" + + // WHEN + let gameSeries = try await service.getGameSeries(.init(name: name)) + + // THEN + #expect(!gameSeries.isEmpty) + #expect(gameSeries.count == 1) + + let gameSeriesName = try #require(gameSeries.first) + + #expect(gameSeriesName.name.contains(name)) + } + + @Test("Get game series by an empty name") + func getGameSeries_byEmptyName() async throws { + + // GIVEN + let name = "" + + // WHEN + let gameSeries = try await service.getGameSeries(.init(name: name)) + + // THEN + #expect(!gameSeries.isEmpty) + #expect(gameSeries.count == 117) + #expect(gameSeries.first?.key == "0x000") + #expect(gameSeries.last?.key == "0x3f0") + } + + @Test("Get the last updated timestamp") + func getLastUpdated() async throws { + // GIVEN + // WHEN + let dateLastUpdated = try await service.getLastUpdated() + + // THEN + let dateComponents = Calendar.current.dateComponents( + [.year, .month, .day], + from: dateLastUpdated + ) + + #expect(dateComponents.year == 2025) + #expect(dateComponents.month == 7) + #expect(dateComponents.day == 18) + } +#endif } diff --git a/Tests/AmiiboService/Types/Clients/AmiiboMockClient.swift b/Tests/AmiiboService/Types/Clients/AmiiboMockClient.swift new file mode 100644 index 0000000..1f901f5 --- /dev/null +++ b/Tests/AmiiboService/Types/Clients/AmiiboMockClient.swift @@ -0,0 +1,217 @@ +//===----------------------------------------------------------------------=== +// +// This source file is part of the AmiiboService open source project +// +// Copyright (c) 2024-2025 Röck+Cöde VoF. and the AmiiboAPI project authors +// Licensed under the EUPL 1.2 or later. +// +// See LICENSE for license information +// See CONTRIBUTORS for the list of AmiiboAPI project authors +// +//===----------------------------------------------------------------------=== + +import AmiiboService +import Foundation + +/// A type that implements a mock client, for testing purposes. +struct AmiiboMockClient { + + // MARK: Properties + + /// A list of amiibo items to return, if any. + private let amiibos: [Amiibo]? + + /// A list of amiibo series to return, if any. + private let amiiboSeries: [AmiiboSeries]? + + /// A list of amiibo types to return, if any. + private let amiiboTypes: [AmiiboType]? + + /// An error to throw, if any. + private let error: AmiiboServiceError? + + /// A list of game characters to return, if any. + private let gameCharacters: [GameCharacter]? + + /// A list of game series to return, if any. + private let gameSeries: [GameSeries]? + + /// A last updated date to return, if any. + private let lastUpdated: Date? + + // MARK: Initializers + + /// Initializes this client. + /// - Parameters: + /// - amiibos: A list of amiibo items to return, if any. + /// - amiiboSeries: A list of amiibo series to return, if any. + /// - amiiboTypes: A list of amiibo types to return, if any. + /// - gameCharacters: A list of game characters to return, if any. + /// - gameSeries: A list of game series to return, if any. + /// - lastUpdated: A last updated date to return, if any. + /// - error: An error to throw, if any. + init( + amiibos: [Amiibo]? = nil, + amiiboSeries: [AmiiboSeries]? = nil, + amiiboTypes: [AmiiboType]? = nil, + gameCharacters: [GameCharacter]? = nil, + gameSeries: [GameSeries]? = nil, + lastUpdated: Date? = nil, + error: AmiiboServiceError? = nil + ) { + self.amiibos = amiibos + self.amiiboSeries = amiiboSeries + self.amiiboTypes = amiiboTypes + self.error = error + self.gameCharacters = gameCharacters + self.gameSeries = gameSeries + self.lastUpdated = lastUpdated + } + +} + +// MARK: - AmiiboClient + +extension AmiiboMockClient: AmiiboClient { + + // MARK: Functions + +#if swift(>=6.0) + func getAmiibos(by filter: AmiiboFilter) async throws(AmiiboServiceError) -> [Amiibo] { + try throwErrorIfExists() + + guard let amiibos else { + throw AmiiboServiceError.notFound + } + + return amiibos + } + + func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws(AmiiboServiceError) -> [AmiiboSeries] { + try throwErrorIfExists() + + guard let amiiboSeries else { + throw AmiiboServiceError.notFound + } + + return amiiboSeries + } + + func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws(AmiiboServiceError) -> [AmiiboType] { + try throwErrorIfExists() + + guard let amiiboTypes else { + throw AmiiboServiceError.notFound + } + + return amiiboTypes + } + + func getGameCharacters(by filter: GameCharacterFilter) async throws(AmiiboServiceError) -> [GameCharacter] { + try throwErrorIfExists() + + guard let gameCharacters else { + throw AmiiboServiceError.notFound + } + + return gameCharacters + } + + func getGameSeries(by filter: GameSeriesFilter) async throws(AmiiboServiceError) -> [GameSeries] { + try throwErrorIfExists() + + guard let gameSeries else { + throw AmiiboServiceError.notFound + } + + return gameSeries + } + + func getLastUpdated() async throws(AmiiboServiceError) -> Date { + try throwErrorIfExists() + + guard let lastUpdated else { + throw AmiiboServiceError.notFound + } + + return lastUpdated + } +#else + func getAmiibos(by filter: AmiiboFilter) async throws -> [Amiibo] { + try throwErrorIfExists() + + guard let amiibos else { + throw AmiiboServiceError.notFound + } + + return amiibos + } + + func getAmiiboSeries(by filter: AmiiboSeriesFilter) async throws -> [AmiiboSeries] { + try throwErrorIfExists() + + guard let amiiboSeries else { + throw AmiiboServiceError.notFound + } + + return amiiboSeries + } + + func getAmiiboTypes(by filter: AmiiboTypeFilter) async throws -> [AmiiboType] { + try throwErrorIfExists() + + guard let amiiboTypes else { + throw AmiiboServiceError.notFound + } + + return amiiboTypes + } + + func getGameCharacters(by filter: GameCharacterFilter) async throws -> [GameCharacter] { + try throwErrorIfExists() + + guard let gameCharacters else { + throw AmiiboServiceError.notFound + } + + return gameCharacters + } + + func getGameSeries(by filter: GameSeriesFilter) async throws -> [GameSeries] { + try throwErrorIfExists() + + guard let gameSeries else { + throw AmiiboServiceError.notFound + } + + return gameSeries + } + + func getLastUpdated() async throws -> Date { + try throwErrorIfExists() + + guard let lastUpdated else { + throw AmiiboServiceError.notFound + } + + return lastUpdated + } +#endif + +} + +// MARK: - Helpers + +private extension AmiiboMockClient { + + // MARK: Functions + + /// Throws an error if it has been provided, + /// - Throws: An ``AmiiboServiceError`` error in case an error has been provided. + func throwErrorIfExists() throws(AmiiboServiceError) { + if let error { + throw error + } + } + +} diff --git a/Sources/AmiiboService/Public/Enumerations/AmiiboClient.swift b/Tests/AmiiboService/Types/Extensions/Tag+Customs.swift similarity index 50% rename from Sources/AmiiboService/Public/Enumerations/AmiiboClient.swift rename to Tests/AmiiboService/Types/Extensions/Tag+Customs.swift index c293758..6b9d64d 100644 --- a/Sources/AmiiboService/Public/Enumerations/AmiiboClient.swift +++ b/Tests/AmiiboService/Types/Extensions/Tag+Customs.swift @@ -10,12 +10,13 @@ // //===----------------------------------------------------------------------=== -/// A representation of the types of client that a ``AmiiboService`` service can utilize. -/// -/// > important: This enumeration has been defined as a way to avoid exposing the `APIClient` protocol outside the boundaries of this library. -public enum AmiiboClient { - /// A live Amiibo client to interact with the online service. - case live(AmiiboLiveClient = .init()) - ///A mock Amiibo client, for testing purposes. - case mock(AmiiboMockClient) +import Testing + +extension Tag { + + // MARK: Properties + + /// Tag that indicates tests against a live backend service. + @Tag static var live: Self + }