diff --git a/IntegrationTests/AnyPublisher+Test.swift b/IntegrationTests/AnyPublisher+Test.swift new file mode 100644 index 0000000..e2aa330 --- /dev/null +++ b/IntegrationTests/AnyPublisher+Test.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) 2023 gematik GmbH +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Combine +import Foundation + +extension AnyPublisher { + /// Convenience function for testing a Publisher's emitted values + func test() throws -> Self.Output { + try testWithTimeout(timeout: 0) + } + + /// Convenience function for testing a Publisher's emitted values + func testWithTimeout(timeout millis: Int = 3000, sleep interval: TimeInterval = 0.1) throws -> Self.Output { + var done = false + var output: Self.Output? + var error: Self.Failure? + let timeoutTime = DispatchTime.now() + DispatchTimeInterval.milliseconds(millis) + let cancellable = sink( + receiveCompletion: { completion in + switch completion { + case .finished: done = true + case let .failure(failure): + error = failure + done = true + } + }, + receiveValue: { receivedValue in + output = receivedValue + } + ) + + while !done && (timeoutTime > DispatchTime.now() || millis <= 0) { + RunLoop.current.run(mode: .default, before: Date(timeIntervalSinceNow: interval)) + } + if !done { + cancellable.cancel() + throw AnyPublisherTestError.timeoutError + } + + if let output = output { + return output + } else if let error = error { + throw error + } else { + throw AnyPublisherTestError.noValuesPublished + } + } +} + +enum AnyPublisherTestError: Error { + case noValuesPublished + case timeoutError +} diff --git a/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift b/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift index 80f3304..1434eb5 100644 --- a/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift +++ b/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class AuthenticateChallengeE256Test: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift b/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift index d5fb600..4e7f601 100644 --- a/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift +++ b/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class AuthenticateChallengeR2048Test: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift b/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift index f7bc295..5f1dfcb 100644 --- a/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class CardChannelTypeExtVersionIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/DetermineCardAidIntegrationTest.swift b/IntegrationTests/HealthCardControl/DetermineCardAidIntegrationTest.swift index c74ff16..f5d6e75 100644 --- a/IntegrationTests/HealthCardControl/DetermineCardAidIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/DetermineCardAidIntegrationTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class DetermineCardAidIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTest.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTest.swift index f9c7a8d..4f06888 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtChangeReferenceDataIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTestCont.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTestCont.swift index fd2df27..78e72cc 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTestCont.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtChangeReferenceDataIntegrationTestCont.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest // Note: This continuation of `HealthCardTypeExtChangeReferenceDataIntegrationTest` exists to separate diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtESIGNIntegrationTest.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtESIGNIntegrationTest.swift index 82e2ff2..f9ecc9b 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtESIGNIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtESIGNIntegrationTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtESIGNIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtEfCardAccessIntTest.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtEfCardAccessIntTest.swift index 98a4a36..33a42fe 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtEfCardAccessIntTest.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtEfCardAccessIntTest.swift @@ -18,7 +18,6 @@ import CardReaderProviderApi import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtEfCardAccessIntTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTest.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTest.swift index 2b7c381..78d5422 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtResetRetryCounterIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestCont.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestCont.swift index 6f7b30b..377beb8 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestCont.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestCont.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest // Note: This continuation of `HealthCardTypeExtResetRetryCounterIntegrationTest` exists to separate the count dependent diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestContCont.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestContCont.swift index d5f5813..7ec0696 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestContCont.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtResetRetryCounterIntegrationTestContCont.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest // Note: This continuation of `HealthCardTypeExtResetRetryCounterIntegrationTest` exists to separate the count dependent diff --git a/IntegrationTests/HealthCardControl/HealthCardTypeExtVerifyPinTest.swift b/IntegrationTests/HealthCardControl/HealthCardTypeExtVerifyPinTest.swift index 066c091..c27ee6e 100644 --- a/IntegrationTests/HealthCardControl/HealthCardTypeExtVerifyPinTest.swift +++ b/IntegrationTests/HealthCardControl/HealthCardTypeExtVerifyPinTest.swift @@ -18,7 +18,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtVerifyPinTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift b/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift index 73e42f7..40236dd 100644 --- a/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift @@ -19,7 +19,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class KeyAgreementIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift b/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift index 56ad277..e71cd60 100644 --- a/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift @@ -20,7 +20,6 @@ import Foundation import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class OpenSecureSessionIntegrationTest: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift b/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift index 0b53658..b900593 100644 --- a/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift +++ b/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift @@ -19,7 +19,6 @@ import HealthCardAccess @testable import HealthCardControl import Nimble import OSLog -import Util import XCTest final class ReadAutCertificateE256Test: CardSimulationTerminalTestCase { diff --git a/IntegrationTests/project.yml b/IntegrationTests/project.yml index c02db51..1304856 100644 --- a/IntegrationTests/project.yml +++ b/IntegrationTests/project.yml @@ -30,12 +30,15 @@ targets: sources: - path: IntegrationTests dependencies: - - target: CardReaderAccess_macOS - - target: CardReaderProviderApi_macOS - - target: HealthCardAccess_macOS - - target: HealthCardControl_macOS - - target: Util_macOS - - framework: Carthage/Build/Nimble.xcframework + - package: Openhealthcardkit + product: CardReaderAccess + - package: Openhealthcardkit + product: CardReaderProviderApi + - package: Openhealthcardkit + product: HealthCardAccess + - package: Openhealthcardkit + product: HealthCardControl + - package: Nimble - target: CardSimulationCardReaderProvider - target: CardSimulationLoader - package: AEXML @@ -123,8 +126,10 @@ targets: dependencies: - target: CardSimulationLoader - package: ASN1Kit - - target: CardReaderProviderApi_macOS - - target: CardReaderAccess_macOS + - package: Openhealthcardkit + product: CardReaderProviderApi + - package: Openhealthcardkit + product: CardReaderAccess - framework: Carthage/Build/SwiftSocket.xcframework transitivelyLinkDependencies: true CardSimulationLoaderTests: @@ -140,18 +145,21 @@ targets: - package: AEXML - target: AEXMLExt - target: CardSimulationLoader - - framework: Carthage/Build/Nimble.xcframework + - package: Nimble gatherCoverageData: true AEXMLExtTests: type: bundle.unit-test platform: macOS bundleIdPrefix: de.gematik.ti.openhealthcard.cardsimulation + settings: + base: + OTHER_SWIFT_FLAGS: -no-verify-emitted-module-interface sources: - CardSimulationTestKit/Tests/AEXMLExtTests dependencies: - target: AEXMLExt - package: AEXML - - framework: Carthage/Build/Nimble.xcframework + - package: Nimble gatherCoverageData: true CardSimulationCardReaderProviderTests: type: bundle.unit-test @@ -165,5 +173,7 @@ targets: dependencies: - target: CardSimulationCardReaderProvider - target: AEXMLExt - - framework: Carthage/Build/Nimble.xcframework + - package: Openhealthcardkit + product: CardReaderAccess + - package: Nimble gatherCoverageData: true \ No newline at end of file diff --git a/Mintfile b/Mintfile index 7b10703..3c390c3 100644 --- a/Mintfile +++ b/Mintfile @@ -1,4 +1,4 @@ realm/SwiftLint@0.44.0 -yonaskolb/xcodegen@2.38.0 +yonaskolb/xcodegen@2.42.0 Carthage/Carthage@0.40.0 nicklockwood/SwiftFormat@0.48.7 \ No newline at end of file diff --git a/Package.resolved b/Package.resolved index bda9331..d1e05be 100644 --- a/Package.resolved +++ b/Package.resolved @@ -39,10 +39,10 @@ { "identity" : "nimble", "kind" : "remoteSourceControl", - "location" : "http://github.com/Quick/Nimble", + "location" : "https://github.com/Quick/Nimble", "state" : { - "revision" : "c93f16c25af5770f0d3e6af27c9634640946b068", - "version" : "9.2.1" + "revision" : "edaedc1ec86f14ac6e2ca495b94f0ff7150d98d0", + "version" : "12.3.0" } }, { diff --git a/Package.swift b/Package.swift index 7bed869..fe1f692 100644 --- a/Package.swift +++ b/Package.swift @@ -9,26 +9,19 @@ let package = Package( .macOS(.v12) ], products: [ - .library( - name: "HealthCardControl", - targets: ["HealthCardControl"]), - .library( - name: "NFCCardReaderProvider", - targets: ["NFCCardReaderProvider"]), - .library( - name: "HealthCardAccess", - targets: ["HealthCardAccess"]), - .library( - name: "CardReaderProviderApi", - targets: ["CardReaderProviderApi"]), - .library( - name: "Helper", - targets: ["Helper"]), + .library(name: "HealthCardControl", targets: ["HealthCardControl"]), + .library(name: "NFCCardReaderProvider", targets: ["NFCCardReaderProvider"]), + .library(name: "HealthCardAccess", targets: ["HealthCardAccess"]), + .library(name: "CardReaderProviderApi", targets: ["CardReaderProviderApi"]), + .library(name: "Helper", targets: ["Helper"]), + // TODO: Remove this (and the .target) at a later time. For now it's only needed for the CardSimulationTests + .library(name: "CardReaderAccess", targets: ["CardReaderAccess"]), ], dependencies: [ .package(url: "https://github.com/gematik/ASN1Kit.git", from: "1.2.0"), .package(url: "https://github.com/gematik/OpenSSL-Swift", from: "4.2.0"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"), + .package(url: "https://github.com/Quick/Nimble", from: "12.0.0"), ], targets: [ .target( @@ -49,7 +42,7 @@ let package = Package( ), .target( name: "HealthCardAccess", - dependencies: ["CardReaderAccess", "CardReaderProviderApi", "ASN1Kit"] + dependencies: ["CardReaderProviderApi", "ASN1Kit"] ), .target( name: "CardReaderAccess", @@ -62,5 +55,27 @@ let package = Package( .target( name: "Helper" ), + .testTarget( + name: "HealthCardControlTests", + dependencies: ["HealthCardControl", "Nimble"], + resources: [ + .process("Resources.bundle") + ] + ), + .testTarget( + name: "HealthCardAccessTests", + dependencies: ["HealthCardAccess", "Nimble"], + resources: [ + .process("Resources.bundle") + ] + ), + .testTarget( + name: "CardReaderAccessTests", + dependencies: ["CardReaderAccess", "Nimble"] + ), + .testTarget( + name: "CardReaderProviderApiTests", + dependencies: ["CardReaderProviderApi", "Nimble"] + ), ] ) diff --git a/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift b/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift index 14d339e..3a577cc 100644 --- a/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift +++ b/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift @@ -266,8 +266,6 @@ extension NFCTagReaderSession.Publisher { } } -#endif - @propertyWrapper struct Synchronized { private let backing: SynchronizedVar @@ -333,3 +331,4 @@ class SynchronizedVar { mutex.unlock() } } +#endif diff --git a/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift b/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift index ca8bbf2..3137b2c 100644 --- a/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift +++ b/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift @@ -69,10 +69,11 @@ final class FileControlParameterTest: XCTestCase { // totalLength == 0xFFFFFFFF // fileIdentifier == 0x3F00 - let filePath = bundle.testResourceFilePath(in: "Resources", for: "FCP/fcp_df_A000000167455349474E_apdu.dat") - guard let responseData = try? filePath.readFileContents() else { - fatalError("FCP/fcp_df_A000000167455349474E_apdu.dat could not be read") - } + let responseData = ResourceLoader.loadResourceAsData( + resource: "fcp_df_A000000167455349474E_apdu", + withExtension: "dat", + directory: "FCP" + ) guard let fcp = try? FileControlParameter.parse(data: responseData) else { Nimble.fail("Could not parse FCP") @@ -96,10 +97,12 @@ final class FileControlParameterTest: XCTestCase { // totalLength == 0xFFFFFFFF // fileIdentifier == NULL - let filePath = bundle.testResourceFilePath(in: "Resources", for: "FCP/fcp_adf_A000000167455349474E_apdu.dat") - guard let responseData = try? filePath.readFileContents() else { - fatalError("FCP/fcp_adf_A000000167455349474E_apdu.dat could not be read") - } + let responseData = ResourceLoader.loadResourceAsData( + resource: "fcp_adf_A000000167455349474E_apdu", + withExtension: "dat", + directory: "FCP" + ) + guard let fcp = try? FileControlParameter.parse(data: responseData) else { Nimble.fail("Could not parse FCP") return @@ -120,10 +123,11 @@ final class FileControlParameterTest: XCTestCase { // totalLength == 0xFFFFFFFF // fileIdentifier == 0x2F02 - let filePath = bundle.testResourceFilePath(in: "Resources", for: "FCP/fcp_nett_length_apdu.dat") - guard let responseData = try? filePath.readFileContents() else { - fatalError("FCP/fcp_nett_length_apdu.dat could not be read") - } + let responseData = ResourceLoader.loadResourceAsData( + resource: "fcp_nett_length_apdu", + withExtension: "dat", + directory: "FCP" + ) guard let fcp = try? FileControlParameter.parse(data: responseData) else { Nimble.fail("Could not parse FCP") diff --git a/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift b/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift index cc25269..88d0257 100644 --- a/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift +++ b/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift @@ -50,12 +50,11 @@ final class GemCvCertificateTest: XCTestCase { }() func testGemCvCertificateDecodingFromASN1() { - let filename = "CVC/EF.C.HPC.AUTR_CVC.E256.der" - let bundle = Bundle(for: GemCvCertificateTest.self) - let certPath = bundle.testResourceFilePath(in: "Resources", for: filename) - guard let certData = try? certPath.readFileContents() else { - fatalError("Could not read: [\(filename)]") - } + let certData = ResourceLoader.loadResourceAsData( + resource: "EF.C.HPC.AUTR_CVC.E256", + withExtension: "der", + directory: "CVC" + ) expect { try GemCvCertificate.from(data: certData) @@ -63,12 +62,11 @@ final class GemCvCertificateTest: XCTestCase { } func testGemCvCertificateEncodingToASN1() { - let filename = "CVC/EF.C.HPC.AUTR_CVC.E256.der" - let bundle = Bundle(for: GemCvCertificateTest.self) - let certPath = bundle.testResourceFilePath(in: "Resources", for: filename) - guard let certData = try? certPath.readFileContents() else { - fatalError("Could not read: [\(filename)]") - } + let certData = ResourceLoader.loadResourceAsData( + resource: "EF.C.HPC.AUTR_CVC.E256", + withExtension: "der", + directory: "CVC" + ) expect { try self.gemCvCertificate.asn1encode() diff --git a/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift b/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift index e32c9c4..2baeb2f 100644 --- a/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift +++ b/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift @@ -121,7 +121,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { func testPsoEncipher_usingTransmittedRsaKey() throws { let dataToBeEnciphered = Data([0x66]) - let pubKeyData = "rsa_pub_key.der".loadAsResource(at: "PSO", bundle: bundle) + let pubKeyData = ResourceLoader.loadResourceAsData( + resource: "rsa_pub_key", + withExtension: "der", + directory: "PSO" + ) var createError: Unmanaged? guard let publicKey = SecKeyCreateWithData(pubKeyData as NSData, [kSecAttrKeyType: kSecAttrKeyTypeRSA, @@ -131,7 +135,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { return } - let apduEncipherRsaPkcs1v15 = "apduEncipherRsaPkcs1v15.dat".loadAsResource(at: "PSO", bundle: bundle) + let apduEncipherRsaPkcs1v15 = ResourceLoader.loadResourceAsData( + resource: "apduEncipherRsaPkcs1v15", + withExtension: "dat", + directory: "PSO" + ) expect { try HealthCardCommand.PsoEncipher .encipherUsingTransmittedRsaKeyPkcs1_v1_5(rsaPublicKey: publicKey, @@ -140,7 +148,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { } == apduEncipherRsaPkcs1v15 // using transmitted RSA Oaep key - let apduEncipherRsaOaep = "apduEncipherRsaOaep.dat".loadAsResource(at: "PSO", bundle: bundle) + let apduEncipherRsaOaep = ResourceLoader.loadResourceAsData( + resource: "apduEncipherRsaOaep", + withExtension: "dat", + directory: "PSO" + ) expect { try HealthCardCommand.PsoEncipher .encipherUsingTransmittedRsaKeyOaep(rsaPublicKey: publicKey, @@ -158,7 +170,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { func testPsoEncipher_usingTransmittedElcKey() { let dataToBeEnciphered = Data([0x66]) - let pubKeyData = "elc_pub_key.der".loadAsResource(at: "PSO", bundle: bundle) + let pubKeyData = ResourceLoader.loadResourceAsData( + resource: "elc_pub_key", + withExtension: "der", + directory: "PSO" + ) var createError: Unmanaged? guard let publicKey = SecKeyCreateWithData(pubKeyData as NSData, [kSecAttrKeyType: kSecAttrKeyTypeEC, @@ -168,7 +184,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { return } - let apduEncipherElc = "apduEncipherElc.dat".loadAsResource(at: "PSO", bundle: bundle) + let apduEncipherElc = ResourceLoader.loadResourceAsData( + resource: "apduEncipherElc", + withExtension: "dat", + directory: "PSO" + ) expect { try HealthCardCommand.PsoEncipher @@ -210,12 +230,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { } func testPsoVerifyGemCvCertificate() throws { - let filename = "CVC/GemCVC.der" - let certPath = bundle.testResourceFilePath(in: "Resources", for: filename) - guard let certData = try? certPath.readFileContents() else { - Nimble.fail("Could not read: [\(filename)]") - return - } + let certData = ResourceLoader.loadResourceAsData( + resource: "GemCVC", + withExtension: "der", + directory: "CVC" + ) let expectedAPDU = Data([0x0, 0x2A, 0x0, 0xBE, 0xDC] + certData) expect { @@ -266,13 +285,13 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { typealias DSATestParameter = (test: String, hash: String, normalized: String, key: String, expected: String, pass: Bool, throw: Bool) let dsaVerifyTests: [DSATestParameter] = [ - (test: "ansix9p256r1", hash: "ansix9p256r1_hash.dat", normalized: "ansix9p256r1_signature_normalized.dat", - key: "ansix9p256r1_ecpubkey.dat", expected: "ansix9p256r1_expected_apdu.dat", pass: true, throw: false), - (test: "ansix9p384r1", hash: "ansix9p384r1_hash.dat", normalized: "ansix9p384r1_signature_normalized.dat", - key: "ansix9p384r1_ecpubkey.dat", expected: "ansix9p384r1_expected_apdu.dat", pass: true, throw: false), - (test: "brainpoolP512r1", hash: "brainpoolP512r1_hash.dat", - normalized: "brainpoolP512r1_signature_normalized.dat", key: "brainpoolP512r1_ecpubkey.dat", - expected: "brainpoolP512r1_expected_apdu.dat", pass: false, throw: true), + (test: "ansix9p256r1", hash: "ansix9p256r1_hash", normalized: "ansix9p256r1_signature_normalized", + key: "ansix9p256r1_ecpubkey", expected: "ansix9p256r1_expected_apdu", pass: true, throw: false), + (test: "ansix9p384r1", hash: "ansix9p384r1_hash", normalized: "ansix9p384r1_signature_normalized", + key: "ansix9p384r1_ecpubkey", expected: "ansix9p384r1_expected_apdu", pass: true, throw: false), + (test: "brainpoolP512r1", hash: "brainpoolP512r1_hash", + normalized: "brainpoolP512r1_signature_normalized", key: "brainpoolP512r1_ecpubkey", + expected: "brainpoolP512r1_expected_apdu", pass: false, throw: true), ] func testPsoVerifyDSA_parameterized() { @@ -290,6 +309,7 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { } } + // swiftlint:disable:next function_body_length func dasVerificationTest(_ testCase: DSATestParameter) { let hash = testCase.hash let signature = testCase.normalized @@ -299,11 +319,27 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { let `throw` = testCase.throw let path = "DSA" - let hashData = hash.loadAsResource(at: path, bundle: bundle) - let normalizedSignature = signature.loadAsResource(at: path, bundle: bundle) - let publicKeyData = publicKey.loadAsResource(at: path, bundle: bundle) + let hashData = ResourceLoader.loadResourceAsData( + resource: hash, + withExtension: "dat", + directory: "DSA" + ) + let normalizedSignature = ResourceLoader.loadResourceAsData( + resource: signature, + withExtension: "dat", + directory: "DSA" + ) + let publicKeyData = ResourceLoader.loadResourceAsData( + resource: publicKey, + withExtension: "dat", + directory: "DSA" + ) - let expectedAPDU = expected.loadAsResource(at: path, bundle: bundle) + let expectedAPDU = ResourceLoader.loadResourceAsData( + resource: expected, + withExtension: "dat", + directory: "DSA" + ) let expectation = expect { () throws -> Data in var error: Unmanaged? guard let publicKey = SecKeyCreateWithData( @@ -405,8 +441,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { } func testPsoVerifyDSA_wrong_hashsize() { - let filename = "ansix9p256r1_ecpubkey.dat" - let ecKeyData = filename.loadAsResource(at: "DSA", bundle: bundle) + let ecKeyData = ResourceLoader.loadResourceAsData( + resource: "ansix9p256r1_ecpubkey", + withExtension: "dat", + directory: "DSA" + ) let signature = Data([UInt8](repeating: 0xF0, count: 64)) let hash = Data([UInt8](repeating: 0xEF, count: 30)) @@ -430,8 +469,11 @@ final class HCCExtPerformSecurityOperationTest: XCTestCase { } func testPsoVerifyDSA_wrong_signaturesize() { - let filename = "ansix9p256r1_ecpubkey.dat" - let ecKeyData = filename.loadAsResource(at: "DSA", bundle: bundle) + let ecKeyData = ResourceLoader.loadResourceAsData( + resource: "ansix9p256r1_ecpubkey", + withExtension: "dat", + directory: "DSA" + ) let signature = Data([UInt8](repeating: 0xF0, count: 66)) let hash = Data([UInt8](repeating: 0xEF, count: 32)) @@ -477,4 +519,5 @@ func throwError() -> Nimble.Predicate { } } -extension String: Error {} +// swiftlint:disable:next file_length +extension String: @retroactive Error {} diff --git a/Tests/HealthCardAccessTests/Models/ECCurveInfoTest.swift b/Tests/HealthCardAccessTests/Models/ECCurveInfoTest.swift index 083767f..19f8504 100644 --- a/Tests/HealthCardAccessTests/Models/ECCurveInfoTest.swift +++ b/Tests/HealthCardAccessTests/Models/ECCurveInfoTest.swift @@ -15,6 +15,7 @@ // import ASN1Kit +import Foundation @testable import HealthCardAccess import Nimble import XCTest @@ -22,33 +23,40 @@ import XCTest final class ECCurveInfoTest: XCTestCase { typealias ECCurveNormalizeTest = (test: String, curve: ECCurveInfo, signature: String, normalized: String) let normalizingCases: [ECCurveNormalizeTest] = [ - (test: "ansix9p256r1", curve: ansix9p256r1, signature: "ansix9p256r1_signature.dat", - normalized: "ansix9p256r1_signature_normalized.dat"), - (test: "ansix9p384r1", curve: ansix9p384r1, signature: "ansix9p384r1_signature.dat", - normalized: "ansix9p384r1_signature_normalized.dat"), - (test: "brainpoolP256r1", curve: brainpoolP256r1, signature: "brainpoolP256r1_signature.dat", - normalized: "brainpoolP256r1_signature_normalized.dat"), - (test: "brainpoolP384r1", curve: brainpoolP384r1, signature: "brainpoolP384r1_signature.dat", - normalized: "brainpoolP384r1_signature_normalized.dat"), - (test: "brainpoolP512r1", curve: brainpoolP512r1, signature: "brainpoolP512r1_signature.dat", - normalized: "brainpoolP512r1_signature_normalized.dat"), + (test: "ansix9p256r1", curve: ansix9p256r1, signature: "ansix9p256r1_signature", + normalized: "ansix9p256r1_signature_normalized"), + (test: "ansix9p384r1", curve: ansix9p384r1, signature: "ansix9p384r1_signature", + normalized: "ansix9p384r1_signature_normalized"), + (test: "brainpoolP256r1", curve: brainpoolP256r1, signature: "brainpoolP256r1_signature", + normalized: "brainpoolP256r1_signature_normalized"), + (test: "brainpoolP384r1", curve: brainpoolP384r1, signature: "brainpoolP384r1_signature", + normalized: "brainpoolP384r1_signature_normalized"), + (test: "brainpoolP512r1", curve: brainpoolP512r1, signature: "brainpoolP512r1_signature", + normalized: "brainpoolP512r1_signature_normalized"), ] let normalizingCasesExpectFailure: [ECCurveNormalizeTest] = [ - (test: "signature sequence too long", curve: ansix9p256r1, signature: - "ansix9p256r1_signature_invalid_toolongsequence.dat", - normalized: "ansix9p256r1_signature_normalized.dat"), + (test: "signature sequence too long", + curve: ansix9p256r1, + signature: "ansix9p256r1_signature_invalid_toolongsequence", + normalized: "ansix9p256r1_signature_normalized"), ] - func testNormalizingSignature() { - let bundle = Bundle(for: ECCurveInfoTest.self) - let path = "DSA" + func testNormalizingSignature() throws { normalizingCases.forEach { (testCase: ECCurveNormalizeTest) in let testName = testCase.test + let signature = ResourceLoader.loadResourceAsData( + resource: testCase.signature, + withExtension: "dat", + directory: "DSA" + ) + let signatureNormalized = ResourceLoader.loadResourceAsData( + resource: testCase.normalized, + withExtension: "dat", + directory: "DSA" + ) let errors = Nimble.gatherFailingExpectations(silently: true) { - expect { - try testCase.curve.normalize(signature: testCase.signature.loadAsResource(at: path, bundle: bundle)) - } == testCase.normalized.loadAsResource(at: path, bundle: bundle) + expect { try testCase.curve.normalize(signature: signature) } == signatureNormalized } if !errors.isEmpty { Nimble.fail("Test (DSA-Normalize): [\(testName)] failed!") @@ -60,13 +68,16 @@ final class ECCurveInfoTest: XCTestCase { } func testNormalizingSignature_expectFailure() { - let bundle = Bundle(for: ECCurveInfoTest.self) - let path = "DSA" normalizingCasesExpectFailure.forEach { (testCase: ECCurveNormalizeTest) in let testName = testCase.test + let signature = ResourceLoader.loadResourceAsData( + resource: testCase.signature, + withExtension: "dat", + directory: "DSA" + ) let errors = Nimble.gatherFailingExpectations(silently: false) { expect { - try testCase.curve.normalize(signature: testCase.signature.loadAsResource(at: path, bundle: bundle)) + try testCase.curve.normalize(signature: signature) }.to(throwError()) } if !errors.isEmpty { @@ -77,9 +88,4 @@ final class ECCurveInfoTest: XCTestCase { } } } - - static let allTests = [ - ("testNormalizingSignature", testNormalizingSignature), - ("testNormalizingSignature_expectFailure", testNormalizingSignature_expectFailure), - ] } diff --git a/Tests/HealthCardAccessTests/ResourceLoader.swift b/Tests/HealthCardAccessTests/ResourceLoader.swift deleted file mode 100644 index 30e0cec..0000000 --- a/Tests/HealthCardAccessTests/ResourceLoader.swift +++ /dev/null @@ -1,108 +0,0 @@ -// swiftlint:disable:this file_name -// -// Copyright (c) 2024 gematik GmbH -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -extension Bundle { - /** - Get the filePath for a resource in a bundle. - - - Parameters: - - bundle: Name of the bundle packaged with this App/Framework Bundle - - filename: The filename of the resource in the bundle - - - Returns: Absolute filePath to the Resources in the bundle - */ - func resourceFilePath(in bundle: String, for filename: String) -> String { - let bundlePath = self.bundlePath - #if os(macOS) - let resourceFilePath = "file://\(bundlePath)/Resources/\(bundle).bundle/\(filename)" - #else - let resourceFilePath = "file://\(bundlePath)/\(bundle).bundle/\(filename)" - #endif - return resourceFilePath - } - - /** - Get the filePath for a test resource in a bundle. - - - Parameters: - - bundle: Name of the bundle packaged with this Test Bundle - - filename: The filename of the resource in the bundle - - - Returns: Absolute filePath to the Resources in the bundle - */ - func testResourceFilePath(in bundle: String, for filename: String) -> String { - let bundlePath = self.bundlePath - #if os(macOS) - let resourceFilePath = "file://\(bundlePath)/Contents/Resources/\(bundle).bundle/\(filename)" - #else - let resourceFilePath = "file://\(bundlePath)/\(bundle).bundle/\(filename)" - #endif - return resourceFilePath - } -} - -extension URL { - /** - Convenience function for Data(contentsOf: URL) - - - Throws: An error in the Cocoa domain, if `url` cannot be read. - - - Returns: Data with contents of the (local) File - */ - func readFileContents() throws -> Data { - try Data(contentsOf: self) - } -} - -extension String { - /// File reading/handling error cases - enum FileReaderError: Error { - /// Indicate the URL was not pointing to a valid Resource - case invalidURL(String) - /// Indicate there was no such file at specified path - case noSuchFileAtPath(String) - } - - /** - Read the contents of a local file at path `self`. - - - Throws: FileReaderError when File not exists | An error in the Cocoa domain, if `url` cannot be read. - - - Returns: Data with contents of the File at path `self` - */ - func readFileContents() throws -> Data { - let mUrl: URL = asURL - guard FileManager.default.fileExists(atPath: mUrl.path) else { - throw FileReaderError.noSuchFileAtPath(self) - } - return try mUrl.readFileContents() - } - - /// Returns path as URL - var asURL: URL { - if hasPrefix("/") { - return URL(fileURLWithPath: self) - } - if let url = URL(string: self) { - return url - } else { - return URL(fileURLWithPath: self) - } - } -} diff --git a/Tests/HealthCardAccessTests/Util/AnyPublisher+Test.swift b/Tests/HealthCardAccessTests/Util/AnyPublisher+Test.swift new file mode 100644 index 0000000..e2aa330 --- /dev/null +++ b/Tests/HealthCardAccessTests/Util/AnyPublisher+Test.swift @@ -0,0 +1,67 @@ +// +// Copyright (c) 2023 gematik GmbH +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Combine +import Foundation + +extension AnyPublisher { + /// Convenience function for testing a Publisher's emitted values + func test() throws -> Self.Output { + try testWithTimeout(timeout: 0) + } + + /// Convenience function for testing a Publisher's emitted values + func testWithTimeout(timeout millis: Int = 3000, sleep interval: TimeInterval = 0.1) throws -> Self.Output { + var done = false + var output: Self.Output? + var error: Self.Failure? + let timeoutTime = DispatchTime.now() + DispatchTimeInterval.milliseconds(millis) + let cancellable = sink( + receiveCompletion: { completion in + switch completion { + case .finished: done = true + case let .failure(failure): + error = failure + done = true + } + }, + receiveValue: { receivedValue in + output = receivedValue + } + ) + + while !done && (timeoutTime > DispatchTime.now() || millis <= 0) { + RunLoop.current.run(mode: .default, before: Date(timeIntervalSinceNow: interval)) + } + if !done { + cancellable.cancel() + throw AnyPublisherTestError.timeoutError + } + + if let output = output { + return output + } else if let error = error { + throw error + } else { + throw AnyPublisherTestError.noValuesPublished + } + } +} + +enum AnyPublisherTestError: Error { + case noValuesPublished + case timeoutError +} diff --git a/Tests/HealthCardAccessTests/Util/ResourceLoader.swift b/Tests/HealthCardAccessTests/Util/ResourceLoader.swift new file mode 100644 index 0000000..80b3473 --- /dev/null +++ b/Tests/HealthCardAccessTests/Util/ResourceLoader.swift @@ -0,0 +1,65 @@ +// +// Copyright (c) 2024 gematik GmbH +// +// Licensed under the Apache License, Version 2.0 (the License); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an 'AS IS' BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +import Foundation +import Nimble +import XCTest + +enum ResourceLoader { + static func loadResource( + resource name: String, + withExtension: String? = nil, + directory: String + ) -> String { + // First try to get the URL for the resource directly + if let resourceURL = Bundle.module.url( + forResource: name, + withExtension: withExtension + ) { + return resourceURL.path + } + + guard let resourceURL = Bundle.module.url( + forResource: name, + withExtension: withExtension, + subdirectory: "Resources.bundle/\(directory)" + ) else { + print("Available resources in bundle: \(Bundle.module.paths(forResourcesOfType: "dat", inDirectory: nil))") + fail("Bundle could not find resource \(name).dat in directory \(directory)") + return "" + } + + return resourceURL.path + } + + static func loadResourceAsData( + resource name: String, + withExtension: String? = nil, + directory: String + ) -> Data { + let resource = loadResource( + resource: name, + withExtension: withExtension, + directory: directory + ) + do { + return try Data(contentsOf: URL(fileURLWithPath: resource)) + } catch { + fail("Could not read resource \(name): \(error)") + return Data() + } + } +} diff --git a/Tests/HealthCardAccessTests/Util/String+File.swift b/Tests/HealthCardAccessTests/Util/String+File.swift deleted file mode 100644 index 05613a4..0000000 --- a/Tests/HealthCardAccessTests/Util/String+File.swift +++ /dev/null @@ -1,28 +0,0 @@ -// -// Copyright (c) 2023 gematik GmbH -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -import Foundation - -extension String { - func loadAsResource(at path: String = "DSA", bundle: Bundle, bundleName: String = "Resources") -> Data { - let filename = "\(path)/\(self)" - let filePath = bundle.testResourceFilePath(in: bundleName, for: filename) - guard let fileData = try? filePath.readFileContents() else { - fatalError("Could not read: [\(filename)]") - } - return fileData - } -} diff --git a/Tests/HealthCardControlTests/ResourceLoader.swift b/Tests/HealthCardControlTests/ResourceLoader.swift index 30e0cec..80b3473 100644 --- a/Tests/HealthCardControlTests/ResourceLoader.swift +++ b/Tests/HealthCardControlTests/ResourceLoader.swift @@ -1,4 +1,3 @@ -// swiftlint:disable:this file_name // // Copyright (c) 2024 gematik GmbH // @@ -16,93 +15,51 @@ // import Foundation +import Nimble +import XCTest -extension Bundle { - /** - Get the filePath for a resource in a bundle. - - - Parameters: - - bundle: Name of the bundle packaged with this App/Framework Bundle - - filename: The filename of the resource in the bundle - - - Returns: Absolute filePath to the Resources in the bundle - */ - func resourceFilePath(in bundle: String, for filename: String) -> String { - let bundlePath = self.bundlePath - #if os(macOS) - let resourceFilePath = "file://\(bundlePath)/Resources/\(bundle).bundle/\(filename)" - #else - let resourceFilePath = "file://\(bundlePath)/\(bundle).bundle/\(filename)" - #endif - return resourceFilePath - } - - /** - Get the filePath for a test resource in a bundle. - - - Parameters: - - bundle: Name of the bundle packaged with this Test Bundle - - filename: The filename of the resource in the bundle - - - Returns: Absolute filePath to the Resources in the bundle - */ - func testResourceFilePath(in bundle: String, for filename: String) -> String { - let bundlePath = self.bundlePath - #if os(macOS) - let resourceFilePath = "file://\(bundlePath)/Contents/Resources/\(bundle).bundle/\(filename)" - #else - let resourceFilePath = "file://\(bundlePath)/\(bundle).bundle/\(filename)" - #endif - return resourceFilePath - } -} - -extension URL { - /** - Convenience function for Data(contentsOf: URL) - - - Throws: An error in the Cocoa domain, if `url` cannot be read. - - - Returns: Data with contents of the (local) File - */ - func readFileContents() throws -> Data { - try Data(contentsOf: self) - } -} - -extension String { - /// File reading/handling error cases - enum FileReaderError: Error { - /// Indicate the URL was not pointing to a valid Resource - case invalidURL(String) - /// Indicate there was no such file at specified path - case noSuchFileAtPath(String) - } - - /** - Read the contents of a local file at path `self`. - - - Throws: FileReaderError when File not exists | An error in the Cocoa domain, if `url` cannot be read. +enum ResourceLoader { + static func loadResource( + resource name: String, + withExtension: String? = nil, + directory: String + ) -> String { + // First try to get the URL for the resource directly + if let resourceURL = Bundle.module.url( + forResource: name, + withExtension: withExtension + ) { + return resourceURL.path + } - - Returns: Data with contents of the File at path `self` - */ - func readFileContents() throws -> Data { - let mUrl: URL = asURL - guard FileManager.default.fileExists(atPath: mUrl.path) else { - throw FileReaderError.noSuchFileAtPath(self) + guard let resourceURL = Bundle.module.url( + forResource: name, + withExtension: withExtension, + subdirectory: "Resources.bundle/\(directory)" + ) else { + print("Available resources in bundle: \(Bundle.module.paths(forResourcesOfType: "dat", inDirectory: nil))") + fail("Bundle could not find resource \(name).dat in directory \(directory)") + return "" } - return try mUrl.readFileContents() + + return resourceURL.path } - /// Returns path as URL - var asURL: URL { - if hasPrefix("/") { - return URL(fileURLWithPath: self) - } - if let url = URL(string: self) { - return url - } else { - return URL(fileURLWithPath: self) + static func loadResourceAsData( + resource name: String, + withExtension: String? = nil, + directory: String + ) -> Data { + let resource = loadResource( + resource: name, + withExtension: withExtension, + directory: directory + ) + do { + return try Data(contentsOf: URL(fileURLWithPath: resource)) + } catch { + fail("Could not read resource \(name): \(error)") + return Data() } } } diff --git a/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift b/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift index 5b60e2d..74754c1 100644 --- a/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift +++ b/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift @@ -19,7 +19,6 @@ import Combine import HealthCardAccess @testable import HealthCardControl import Nimble -import Util import XCTest final class HealthCardTypeExtESIGNTest: XCTestCase { @@ -77,16 +76,13 @@ final class HealthCardTypeExtESIGNTest: XCTestCase { } func testReadAutCertificate_publisher() { - let fcpResourcesPath = - URL(fileURLWithPath: #file) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Resources.bundle") - .appendingPathComponent("FCP") - .appendingPathComponent("fcp_A000000167455349474E.dat") - + let fcpResources = ResourceLoader.loadResourceAsData( + resource: "fcp_A000000167455349474E", + withExtension: "dat", + directory: "FCP" + ) // swiftlint:disable:next force_try - let fcp = try! FileControlParameter.parse(data: fcpResourcesPath.readFileContents()) + let fcp = try! FileControlParameter.parse(data: fcpResources) let certSize = Int(fcp.size) let mockCertificate = Data([UInt8](repeating: 0x55, count: certSize)) @@ -102,7 +98,7 @@ final class HealthCardTypeExtESIGNTest: XCTestCase { if command == selectCommand { return try APDU.Response(body: Data(), sw1: 0x90, sw2: 0x0) } else if command == selectEfCommand { - return try APDU.Response(body: fcpResourcesPath.readFileContents(), sw1: 0x90, sw2: 0x0) + return try APDU.Response(body: fcpResources, sw1: 0x90, sw2: 0x0) } else if command == readCommand { return try APDU.Response(body: mockCertificate, sw1: 0x90, sw2: 0x0) } @@ -122,16 +118,13 @@ final class HealthCardTypeExtESIGNTest: XCTestCase { } func testReadAutCertificate() async throws { - let fcpResourcesPath = - URL(fileURLWithPath: #file) - .deletingLastPathComponent() - .deletingLastPathComponent() - .appendingPathComponent("Resources.bundle") - .appendingPathComponent("FCP") - .appendingPathComponent("fcp_A000000167455349474E.dat") - + let fcpResources = ResourceLoader.loadResourceAsData( + resource: "fcp_A000000167455349474E", + withExtension: "dat", + directory: "FCP" + ) // swiftlint:disable:next force_try - let fcp = try! FileControlParameter.parse(data: fcpResourcesPath.readFileContents()) + let fcp = try! FileControlParameter.parse(data: fcpResources) let certSize = Int(fcp.size) let mockCertificate = Data([UInt8](repeating: 0x55, count: certSize)) @@ -147,7 +140,7 @@ final class HealthCardTypeExtESIGNTest: XCTestCase { if command == selectCommand { return try APDU.Response(body: Data(), sw1: 0x90, sw2: 0x0) } else if command == selectEfCommand { - return try APDU.Response(body: fcpResourcesPath.readFileContents(), sw1: 0x90, sw2: 0x0) + return try APDU.Response(body: fcpResources, sw1: 0x90, sw2: 0x0) } else if command == readCommand { return try APDU.Response(body: mockCertificate, sw1: 0x90, sw2: 0x0) } diff --git a/Tests/Util/AnyPublisher+Test.swift b/Tests/HealthCardControlTests/Util/AnyPublisher+Test.swift similarity index 100% rename from Tests/Util/AnyPublisher+Test.swift rename to Tests/HealthCardControlTests/Util/AnyPublisher+Test.swift diff --git a/Tests/NFCCardReaderProviderTests/Test.swift b/Tests/NFCCardReaderProviderTests/Test.swift deleted file mode 100644 index 514bb99..0000000 --- a/Tests/NFCCardReaderProviderTests/Test.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// Copyright (c) 2023 gematik GmbH -// -// Licensed under the Apache License, Version 2.0 (the License); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an 'AS IS' BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -// Placeholder diff --git a/Tests/Util/Resources/Util_Info.plist b/Tests/Util/Resources/Util_Info.plist deleted file mode 100644 index 6c40a6c..0000000 --- a/Tests/Util/Resources/Util_Info.plist +++ /dev/null @@ -1,22 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleVersion - 1 - - diff --git a/project.yml b/project.yml index fb51291..a1b880e 100644 --- a/project.yml +++ b/project.yml @@ -7,14 +7,14 @@ include: options: bundleIdPrefix: de.gematik.ti.ohcapp4ios deploymentTarget: - macOS: 11.0 + macOS: 12.0 iOS: 17.0 minimumXcodeGenVersion: 2.3.0 schemes: AllTests_iOS: build: targets: - NFCDemo: all + ohcKitDummy_iOS: test test: language: de region: DE @@ -22,22 +22,21 @@ schemes: coverageTargets: - NFCDemo targets: - - CardReaderProviderApiTests_iOS - - CardReaderAccessTests_iOS - - HealthCardAccessTests_iOS - - HealthCardControlTests_iOS - - NFCCardReaderProviderTests - NFCDemoTests + - package: Openhealthcardkit/CardReaderProviderApiTests + - package: Openhealthcardkit/CardReaderAccessTests + - package: Openhealthcardkit/HealthCardAccessTests + - package: Openhealthcardkit/HealthCardControlTests AllTests_macOS: build: targets: - CardReaderAccess_macOS: test + ohcKitDummy_macOS: test test: targets: - - CardReaderProviderApiTests_macOS - - CardReaderAccessTests_macOS - - HealthCardAccessTests_macOS - - HealthCardControlTests_macOS + - package: Openhealthcardkit/CardReaderProviderApiTests + - package: Openhealthcardkit/CardReaderAccessTests + - package: Openhealthcardkit/HealthCardAccessTests + - package: Openhealthcardkit/HealthCardControlTests AllSnapshotTests: build: targets: @@ -52,6 +51,8 @@ schemes: - NFCDemoTests packages: + Openhealthcardkit: + path: ./ ASN1Kit: url: https://github.com/gematik/ASN1Kit majorVersion: 1.2.0 @@ -73,6 +74,9 @@ packages: SwiftyXMLParser: url: https://github.com/yahoojapan/SwiftyXMLParser majorVersion: 5.6.0 + Nimble: + url: https://github.com/Quick/Nimble + majorVersion: 12.0.0 settings: base: DEVELOPMENT_TEAM: A9FL89PFFL @@ -107,16 +111,22 @@ targets: - NFCDemoTests gatherCoverageData: false dependencies: - - target: CardReaderProviderApi_iOS - - target: CardReaderAccess_iOS - - target: NFCCardReaderProvider - - target: Helper_iOS + - package: Openhealthcardkit + product: CardReaderProviderApi + - package: Openhealthcardkit + product: CardReaderAccess + - package: Openhealthcardkit + product: NFCCardReaderProvider + - package: Openhealthcardkit + product: Helper - package: ASN1Kit - package: OpenSSL-Swift - package: Gzip - package: SwiftyXMLParser - - target: HealthCardAccess_iOS - - target: HealthCardControl_iOS + - package: Openhealthcardkit + product: HealthCardAccess + - package: Openhealthcardkit + product: HealthCardControl - sdk: CoreNFC.framework - sdk: Combine.framework - sdk: SwiftUI.framework @@ -132,154 +142,12 @@ targets: dependencies: - target: NFCDemo - package: SnapshotTesting - CardReaderProviderApi: - type: framework - platform: [iOS,macOS] - sources: - - Sources/CardReaderProviderApi - info: - path: Resources/CardReaderProviderApi_Info.plist - dependencies: - - target: Helper_${platform} - scheme: - testTargets: - - CardReaderProviderApiTests_${platform} - gatherCoverageData: true - CardReaderAccess: - type: framework - platform: [iOS,macOS] - sources: - - Sources/CardReaderAccess - info: - path: Resources/CardReaderAccess_Info.plist - dependencies: - - target: CardReaderProviderApi_${platform} - - target: Helper_${platform} - scheme: - testTargets: - - CardReaderAccessTests_${platform} - gatherCoverageData: true - Helper: + ohcKitDummy: type: framework - platform: [iOS,macOS] - sources: - - Sources/Helper - info: - path: Resources/Helper_Info.plist - scheme: - gatherCoverageData: true - CardReaderProviderApiTests: - type: bundle.unit-test - platform: [macOS,iOS] - info: - path: Resources/CardReaderProviderApiTests_Info.plist - sources: - - Tests/CardReaderProviderApiTests - dependencies: - - target: CardReaderProviderApi_${platform} - - framework: Carthage/Build/Nimble.xcframework - CardReaderAccessTests: - type: bundle.unit-test - platform: [macOS,iOS] - info: - path: Resources/CardReaderAccessTests_Info.plist - sources: - - Tests/CardReaderAccessTests - dependencies: - - target: CardReaderAccess_${platform} - - framework: Carthage/Build/Nimble.xcframework - HealthCardAccess: - type: framework - platform: [macOS,iOS] - info: - path: Resources/HealthCardAccess_Info.plist - sources: - - Sources/HealthCardAccess - dependencies: - - sdk: Combine.framework - - target: CardReaderAccess_${platform} - - target: CardReaderProviderApi_${platform} - - package: ASN1Kit - transitivelyLinkDependencies: true - scheme: - testTargets: - - HealthCardAccessTests_${platform} - gatherCoverageData: true - HealthCardAccessTests: - type: bundle.unit-test platform: [macOS,iOS] - info: - path: Resources/HealthCardAccessTests_Info.plist - sources: - - path: Tests/HealthCardAccessTests - dependencies: - - target: HealthCardAccess_${platform} - - package: ASN1Kit - - framework: Carthage/Build/Nimble.xcframework - - target: Util_${platform} - HealthCardControl: - type: framework - platform: [iOS,macOS] - info: - path: Resources/HealthCardControl_Info.plist - sources: - - path: Sources/HealthCardControl - dependencies: - - target: HealthCardAccess_${platform} - - target: Helper_${platform} - - package: OpenSSL-Swift - transitivelyLinkDependencies: true - scheme: - testTargets: - - HealthCardControlTests_${platform} - gatherCoverageData: true - HealthCardControlTests: - name: HealthCardControlTests_${platform} - type: bundle.unit-test - platform: [macOS,iOS] - info: - path: Resources/HealthCardControlTests_Info.plist - sources: - - path: Tests/HealthCardControlTests - dependencies: - - target: HealthCardControl_${platform} - - target: Util_${platform} - - framework: Carthage/Build/Nimble.xcframework - - sdk: Combine.framework - NFCCardReaderProvider: - type: framework - platform: iOS - info: - path: Resources/NFCCardReaderProvider_Info.plist - sources: - - Sources/NFCCardReaderProvider - dependencies: - - target: HealthCardAccess_iOS - - target: HealthCardControl_iOS - - target: Helper_iOS - - sdk: CoreNFC.framework - scheme: - testTargets: - - NFCCardReaderProviderTests - gatherCoverageData: true - NFCCardReaderProviderTests: - type: bundle.unit-test - platform: iOS - info: - path: Resources/NFCCardReaderProviderTests_Info.plist - sources: - - Tests/NFCCardReaderProviderTests - dependencies: - - target: NFCCardReaderProvider - - framework: Carthage/Build/Nimble.xcframework - Util: - type: framework - platform: [macOS,iOS] - info: - path: Resources/Util_Info.plist + settings: + GENERATE_INFOPLIST_FILE: YES sources: - - Tests/Util - dependencies: - - sdk: Combine.framework + - Sources/CardReaderProviderApi/Card/CardError.swift buildImplicitDependencies: true