diff --git a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCard.swift b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCard.swift index 77affea..826801f 100644 --- a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCard.swift +++ b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCard.swift @@ -16,7 +16,7 @@ import CardReaderProviderApi import Foundation -import GemCommonsKit +import OSLog import SwiftSocket public class SimulatorCard: CardType { @@ -36,7 +36,7 @@ public class SimulatorCard: CardType { required init(host: String, port: Int32, channel protocol: CardProtocol = .t1, timeout: Int = 10) { self.protocol = `protocol` - atr = Data.empty + atr = Data() self.host = host self.port = port connectTimeout = timeout @@ -59,18 +59,18 @@ public class SimulatorCard: CardType { } public func openLogicChannel() throws -> CardChannelType { - throw CardError.connectionError(CommonError.notImplementedError) + throw CardError.connectionError(nil) } public func openLogicChannelAsync() async throws -> CardChannelType { - throw CardError.connectionError(CommonError.notImplementedError) + throw CardError.connectionError(nil) } public func disconnect(reset _: Bool) throws { do { try basicChannel?.close() } catch { - ALog("Error while closing basicChannel: [\(error)]") + Logger.cardSimulationCardReaderProvider.fault("Error while closing basicChannel: [\(error)]") } } @@ -78,7 +78,7 @@ public class SimulatorCard: CardType { do { try disconnect(reset: false) } catch { - ALog("Error while deinit: [\(error)]") + Logger.cardSimulationCardReaderProvider.fault("Error while deinit: [\(error)]") } } diff --git a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCardChannel.swift b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCardChannel.swift index e8dd960..ad88570 100644 --- a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCardChannel.swift +++ b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Card/SimulatorCardChannel.swift @@ -16,7 +16,6 @@ import CardReaderProviderApi import Foundation -import GemCommonsKit import OSLog import SwiftSocket diff --git a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReader.swift b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReader.swift index fdf23a6..f8c87d5 100644 --- a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReader.swift +++ b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReader.swift @@ -17,7 +17,6 @@ import CardReaderProviderApi import CardSimulationLoader import Foundation -import GemCommonsKit public class SimulatorCardReader: CardReaderType { public enum CardReaderError: Error { diff --git a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReaderController.swift b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReaderController.swift index 596808e..5094a7e 100644 --- a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReaderController.swift +++ b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/Terminal/SimulatorCardReaderController.swift @@ -17,7 +17,6 @@ import CardReaderProviderApi import CardSimulationLoader import Foundation -import GemCommonsKit public class SimulatorCardReaderController: CardReaderControllerType { public let name = SimulatorCardReaderProvider.name @@ -78,3 +77,137 @@ extension SimulatorCardReaderController: SimulationManagerDelegate { } } } + +/// A Collection similar to an array, but wraps its Elements in a `WeakRef`. +class WeakArray { + private var _array = [WeakRef]() + + /// Initialize an empty WeakArray + init() {} + + /// Add an object reference to the array + /// - Parameter object: the object to weak reference before adding it to the array + func add(object: T) { + let ref = makePointer(object) + _array.append(ref) + } + + /// Dereference the object at index when not released + /// - Parameter index: index to get + /// - Returns: The object when not deinitialized + func object(at index: Int) -> T? { + guard index < count, let pointer = _array[index].value else { + return nil + } + guard let object = pointer as? T else { + return nil + } + return object + } + + /// Insert an object reference at a specified index + /// - Parameters: + /// - object: the object to weak reference before adding it to the array + /// - index: the index to insert at + func insert(object: T, at index: Int) { + guard index < count else { + return + } + _array.insert(makePointer(object), at: index) + } + + /// Replace a weak reference with a new object + /// - Parameters: + /// - index: the index to replace + /// - object: the object to weak reference before replacing the reference at index + func replaceObject(at index: Int, with object: T) { + guard index < count else { + return + } + _array[index] = makePointer(object) + } + + /// Remove an object reference at a specified index + /// - Parameter index: index of the reference to remove + func removeObject(at index: Int) { + guard index < count else { + return + } + _array.remove(at: index) + } + + /// Get the current count of available (not-released) object references + /// - Note: complexity O(n) - since we filter out the zeroed `WeakRef`s + /// - Returns: the current active reference count + var count: Int { + _array = _array.filter { $0.value != nil } + return _array.count + } + + /// Dereference the object at index when not released + /// - Parameter index: index to get + /// - See: object(at:) + /// - Returns: The object when not deinitialized + subscript(index: Int) -> T? { + object(at: index) + } + + /// Find the index of an object in the array + /// - Parameter object: the object to search for + /// - Note: complexity O(2n) + /// - Returns: the index when found else nil + func index(of object: T) -> Int? { + let anyObject = object as AnyObject + for index in 0 ..< count { + if let current = self[index] as AnyObject?, current === anyObject { + return index + } + } + return nil + } +} + +private func makePointer(_ object: Any) -> WeakRef { + let strongObject = object as AnyObject + let ref = WeakRef(strongObject) + return ref +} + +extension WeakArray { + /// Convenience initializer for weak referencing an entire array + /// - Parameter objects: the object to weak reference in the newly initialized WeakArray + convenience init(objects: [T]) { + self.init() + objects.forEach { + add(object: $0) + } + } + + /// Get objects referenced by `Self` as a strong array + /// - Returns: Array with available objects + var array: [T] { + _array.compactMap { + $0.value as? T + } + } +} + +extension Array where Element: AnyObject { + /// Create a WeakArray with elements from `Self` + /// - Returns: WeakArray with references to all Elements in `Self` + var weakArray: WeakArray { + WeakArray(objects: self) + } +} + +/// Swift object that holds a weak reference to an Object like its Java counter-part WeakReference. +class WeakRef { + /// The weak referenced object + private(set) weak var value: T? + + /// Initialize a weak reference. + /// - Parameter obj: the object to weak reference + required init(_ obj: T) { + value = obj + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/internal/TCPClient+Streaming.swift b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/internal/TCPClient+Streaming.swift index 606977d..92a04b6 100644 --- a/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/internal/TCPClient+Streaming.swift +++ b/CardSimulationTestKit/Sources/CardSimulationCardReaderProvider/internal/TCPClient+Streaming.swift @@ -15,7 +15,7 @@ // import Foundation -import GemCommonsKit +import OSLog import SwiftSocket extension TCPClient: TCPClientType { @@ -33,7 +33,7 @@ extension TCPClient: TCPClientType { let bufferSize = min(Int(availableBytes), len) guard let bytes = read(bufferSize) else { - ALog("Read error") + Logger.cardSimulationCardReaderProvider.fault("Read error") return -1 } buffer.assign(from: bytes, count: bytes.count) diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/KeepAliveRunLoop.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/KeepAliveRunLoop.swift index 33339fc..ef96c92 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/KeepAliveRunLoop.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/KeepAliveRunLoop.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import OSLog /** diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationManager.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationManager.swift index a3327a2..a586c1e 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationManager.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationManager.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import OSLog /// Protocol that describes G2-Kartensimulation Configuration files (pre-)processors @@ -113,7 +112,9 @@ public protocol SimulationManagerType { public class SimulationManager { /// Singleton instance of `SimulationManager` public static let shared = { - SimulationManager() + SimulationManager(tempDir: NSTemporaryDirectory().asURL.appendingPathComponent( + ProcessInfo.processInfo.globallyUniqueString, isDirectory: true + )) }() /// The default G2-Kartensimulation version @@ -137,9 +138,7 @@ public class SimulationManager { /// - Parameters: /// - tempDir: path to a directory to be used as temporary directory for storing dependencies and configuration. /// - Returns: a new SimulationManger - public init(tempDir: URL = NSTemporaryDirectory().asURL.appendingPathComponent( - ProcessInfo.processInfo.globallyUniqueString, isDirectory: true - )) { + public init(tempDir: URL) { Logger.cardSimulationLoader.debug("Init with tempDir: [\(tempDir)]") tempDirectory = tempDir } @@ -202,7 +201,8 @@ public class SimulationManager { guard let simClassPath = info.simulatorClassPath else { throw SimulationLoaderError.malformedConfiguration } - let simulator = SimulationRunner(simulator: file, classPath: simClassPath) + let currentDir = FileManager.default.currentDirectoryPath.asURL + let simulator = SimulationRunner(simulator: file, classPath: simClassPath, workingDirectory: currentDir) simulator.delegate = self _runners.append((url: file, simulator: simulator)) return simulator @@ -242,7 +242,7 @@ public class SimulationManager { do { try FileManager.default.removeItem(at: $0.url) } catch { - ALog("Failed to clean simulator runner environment: [\(error)]") + Logger.cardSimulationLoader.fault("Failed to clean simulator runner environment: [\(error)]") } } /// Remove the simulation from the runners array @@ -262,7 +262,7 @@ public class SimulationManager { do { try FileManager.default.removeItem(at: tempDirectory) } catch { - ALog("Failed to clean [\(error)]") + Logger.cardSimulationLoader.fault("Failed to clean [\(error)]") } } } diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationRunner.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationRunner.swift index 91ba26a..e53f8cd 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationRunner.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/SimulationRunner.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import OSLog import StreamReader @@ -87,7 +86,7 @@ public class SimulationRunner { */ public required init(simulator file: URL, classPath: URL, - workingDirectory dir: URL = FileManager.default.currentDirectoryPath.asURL, + workingDirectory dir: URL, in thread: KeepAliveRunLoop = KeepAliveRunLoop()) { simulatorConfig = file javaClassPath = classPath diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/exception/ExceptionCatcher.m b/CardSimulationTestKit/Sources/CardSimulationLoader/exception/ExceptionCatcher.m new file mode 100644 index 0000000..efb454e --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/exception/ExceptionCatcher.m @@ -0,0 +1,17 @@ +// +// Copyright (c) 2022 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 "ExceptionCatcher.h" diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/exception/include/ExceptionCatcher.h b/CardSimulationTestKit/Sources/CardSimulationLoader/exception/include/ExceptionCatcher.h new file mode 100644 index 0000000..0b04823 --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/exception/include/ExceptionCatcher.h @@ -0,0 +1,42 @@ +// +// 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 + +/** + Catch NSExceptions from ObjC dependencies. + + To use this function create a Bridging-Header and import this header file. + Then you'll just have to call: + + ```swift + if let error = gemTryBlock({ + // Execute code that can raise NSException(s) + }) { + // Handle the exception/error + print("An exception was thrown!", error.localizedDescription) + } + ``` + */ +NS_INLINE NSException * _Nullable gemTryBlock(void(^_Nonnull tryBlock)(void)) { + @try { + tryBlock(); + } + @catch (NSException *exception) { + return exception; + } + return nil; +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/JavaProcess.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/JavaProcess.swift index 33e6d91..e34132f 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/JavaProcess.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/JavaProcess.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import OSLog protocol JavaProcessConfig { @@ -111,7 +110,7 @@ extension JavaProcess { delegate: JavaProcessUpdateDelegate? = nil) { #if os(macOS) || os(Linux) guard process == nil else { - ALog("WARN: double start. Process already started/initialized") + Logger.cardSimulationLoader.warning("WARN: double start. Process already started/initialized") return } #endif diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationManager+Internal.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationManager+Internal.swift index 7d2ee1b..4c568b6 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationManager+Internal.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationManager+Internal.swift @@ -16,7 +16,6 @@ import AEXML import Foundation -import GemCommonsKit import OSLog extension SimulationManager { diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationRunner+JavaProcessDelegate.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationRunner+JavaProcessDelegate.swift index 19fc01f..d1bc576 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationRunner+JavaProcessDelegate.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/internal/SimulationRunner+JavaProcessDelegate.swift @@ -15,8 +15,6 @@ // import Foundation -import GemCommonsKit -import ObjCCommonsKit import OSLog extension SimulationRunner: JavaProcessUpdateDelegate { @@ -60,7 +58,7 @@ extension SimulationRunner: JavaProcessUpdateDelegate { } while line != nil }) { // Caught NSException - ALog("Raised NSException while reading Process stdout") + Logger.cardSimulationLoader.fault("Raised NSException while reading Process stdout") Logger.cardSimulationLoader.debug("NSException: \(exception)") } diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/support/BlockingVar.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/support/BlockingVar.swift new file mode 100644 index 0000000..86ca5a7 --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/support/BlockingVar.swift @@ -0,0 +1,81 @@ +// +// Copyright (c) 2022 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 OSLog + +/** + BlockingVar blocks the [value.get] call until the [value.set] has set the value. + + Note: be aware of blocking the main-thread when the getter is + invoked from the main-thread. + */ +class BlockingVar { + private enum State: Int { + case empty = 0 + case fulfilled + } + + private var _value: T! + private let lock: NSConditionLock + + /// Initialize w/o value + init() { + lock = NSConditionLock(condition: State.empty.rawValue) + } + + /// Initialize w/ value value + init(_ value: T) { + _value = value + lock = NSConditionLock(condition: State.fulfilled.rawValue) + } + + /// Access value + var value: T { + get { + if Thread.isMainThread { + // wait for self.isFulfilled + while !isFulfilled { + Logger.cardSimulationLoader.info("Caution: trying to obtain a lock on the main thread") + RunLoop.current.run(mode: .default, before: Date(timeIntervalSinceNow: 0.001)) + } + } + /// Obtain a lock when the condition is fulfilled. This may seem counter intuitive since, + /// we want to wait/lock while empty and continue when fulfilled. + /// So what lock(whenCondition:) actually does, is waiting/blocking execution until the lock + /// unlocks with fulfilled. Then and only then the lock can be obtained and execution resumed. + lock.lock(whenCondition: State.fulfilled.rawValue) + defer { + /// Of course we unlock the lock so consecutive calls make it through as well. + lock.unlock(withCondition: State.fulfilled.rawValue) + } + return _value + } + set { + /// Obtain a lock before writing the value + lock.lock() + _value = newValue + /// Unlock stating that we have fulfilled the value + lock.unlock(withCondition: State.fulfilled.rawValue) + } + } + + /// Non-blocking check whether self has been fulfilled or not + /// - Returns: `true` on .fulfilled `false` when .empty + var isFulfilled: Bool { + lock.condition == State.fulfilled.rawValue + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/support/Data+IO.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/support/Data+IO.swift new file mode 100644 index 0000000..ad4d18e --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/support/Data+IO.swift @@ -0,0 +1,41 @@ +// +// 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 Data { + /// Result Tuple/Pair with information about the write action. + /// Where it was written and what was written. + typealias WriteResult = (url: URL, data: Data) + + /** + Save Data to file and capture response/exception in Result + + - Parameters: + - file: the URL file/path to write to + - options: Writing settings. Default: .atomicWrite + + - Returns: Result of the write by returning the URL and self upon success. + */ + func save(to file: URL, options: WritingOptions = .atomicWrite) -> Result { + Result { + try FileManager.default.createDirectory(at: file.deletingLastPathComponent(), + withIntermediateDirectories: true) + try self.write(to: file, options: options) + return (file, self) + } + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/support/ResourceLoader.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/support/ResourceLoader.swift new file mode 100644 index 0000000..718a65f --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/support/ResourceLoader.swift @@ -0,0 +1,119 @@ +// 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) + } + } + + static func urlFrom(string: String) -> URL { + if string.hasPrefix("/") { + return URL(fileURLWithPath: string) + } + if let url = URL(string: string) { + return url + } else { + return URL(fileURLWithPath: string) + } + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/support/SynchronizedVar.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/support/SynchronizedVar.swift new file mode 100644 index 0000000..2317e4f --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/support/SynchronizedVar.swift @@ -0,0 +1,55 @@ +// +// 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 + +/** + Thread-Safe variable wrapper. + + Makes sure the get and set are happening synchronously by using + a Mutex for reader/writing to the wrapped value + */ +class SynchronizedVar { + private var _value: T + private let mutex = NSRecursiveLock() + + /// Canonical constructor + init(_ value: T) { + _value = value + } + + /** + Get/Set the value for this SynchronizedVar in a + thread-safe (blocking) manner + */ + var value: T { + mutex.lock() + defer { + mutex.unlock() + } + return _value + } + + /// Set a new value in a transaction to make sure there is no potential 'gap' between get and consecutive set + /// + /// - Parameter block: the transaction that gets the oldValue and must return the newValue that will be stored + /// in the backing value. + func set(transaction block: @escaping (T) -> T) { + mutex.lock() + _value = block(_value) + mutex.unlock() + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/support/WeakArray.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/support/WeakArray.swift new file mode 100644 index 0000000..21b24e0 --- /dev/null +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/support/WeakArray.swift @@ -0,0 +1,151 @@ +// +// Copyright (c) 2022 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 + +/// A Collection similar to an array, but wraps its Elements in a `WeakRef`. +class WeakArray { + private var _array = [WeakRef]() + + /// Initialize an empty WeakArray + init() {} + + /// Add an object reference to the array + /// - Parameter object: the object to weak reference before adding it to the array + func add(object: T) { + let ref = makePointer(object) + _array.append(ref) + } + + /// Dereference the object at index when not released + /// - Parameter index: index to get + /// - Returns: The object when not deinitialized + func object(at index: Int) -> T? { + guard index < count, let pointer = _array[index].value else { + return nil + } + guard let object = pointer as? T else { + return nil + } + return object + } + + /// Insert an object reference at a specified index + /// - Parameters: + /// - object: the object to weak reference before adding it to the array + /// - index: the index to insert at + func insert(object: T, at index: Int) { + guard index < count else { + return + } + _array.insert(makePointer(object), at: index) + } + + /// Replace a weak reference with a new object + /// - Parameters: + /// - index: the index to replace + /// - object: the object to weak reference before replacing the reference at index + func replaceObject(at index: Int, with object: T) { + guard index < count else { + return + } + _array[index] = makePointer(object) + } + + /// Remove an object reference at a specified index + /// - Parameter index: index of the reference to remove + func removeObject(at index: Int) { + guard index < count else { + return + } + _array.remove(at: index) + } + + /// Get the current count of available (not-released) object references + /// - Note: complexity O(n) - since we filter out the zeroed `WeakRef`s + /// - Returns: the current active reference count + var count: Int { + _array = _array.filter { $0.value != nil } + return _array.count + } + + /// Dereference the object at index when not released + /// - Parameter index: index to get + /// - See: object(at:) + /// - Returns: The object when not deinitialized + subscript(index: Int) -> T? { + object(at: index) + } + + /// Find the index of an object in the array + /// - Parameter object: the object to search for + /// - Note: complexity O(2n) + /// - Returns: the index when found else nil + func index(of object: T) -> Int? { + let anyObject = object as AnyObject + for index in 0 ..< count { + if let current = self[index] as AnyObject?, current === anyObject { + return index + } + } + return nil + } +} + +private func makePointer(_ object: Any) -> WeakRef { + let strongObject = object as AnyObject + let ref = WeakRef(strongObject) + return ref +} + +extension WeakArray { + /// Convenience initializer for weak referencing an entire array + /// - Parameter objects: the object to weak reference in the newly initialized WeakArray + convenience init(objects: [T]) { + self.init() + objects.forEach { + add(object: $0) + } + } + + /// Get objects referenced by `Self` as a strong array + /// - Returns: Array with available objects + var array: [T] { + _array.compactMap { + $0.value as? T + } + } +} + +extension Array where Element: AnyObject { + /// Create a WeakArray with elements from `Self` + /// - Returns: WeakArray with references to all Elements in `Self` + var weakArray: WeakArray { + WeakArray(objects: self) + } +} + +/// Swift object that holds a weak reference to an Object like its Java counter-part WeakReference. +class WeakRef { + /// The weak referenced object + private(set) weak var value: T? + + /// Initialize a weak reference. + /// - Parameter obj: the object to weak reference + required init(_ obj: T) { + value = obj + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/URL+ConfigurationFileProcessor.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/URL+ConfigurationFileProcessor.swift index 8319d56..900e8e5 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/URL+ConfigurationFileProcessor.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/URL+ConfigurationFileProcessor.swift @@ -16,7 +16,6 @@ import AEXML import Foundation -import GemCommonsKit /** This extension is supposed to copy the configuration file to a tmp path diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPath.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPath.swift index a9224a2..ec1c4a0 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPath.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPath.swift @@ -152,3 +152,20 @@ extension AEXMLDocument { return true } } + +extension String { + /** + Returns the nth found group by the pattern matched as a string. + */ + public func match(pattern: String, group number: Int = 1) -> String? { + guard let regex = try? NSRegularExpression(pattern: "\(pattern)") else { + return nil + } + let result = regex.matches(in: self, options: [], range: NSRange(location: 0, length: count)) + guard !result.isEmpty, result[0].numberOfRanges > 1, result[0].numberOfRanges > number else { + return nil + } + + return (self as NSString).substring(with: result[0].range(at: number)) + } +} diff --git a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPathManipulator.swift b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPathManipulator.swift index 10bfd29..97e437e 100644 --- a/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPathManipulator.swift +++ b/CardSimulationTestKit/Sources/CardSimulationLoader/xml/XMLPathManipulator.swift @@ -96,8 +96,10 @@ extension XMLPathManipulatorHolder { - Returns: XML manipulator that modifies relative path for the give path */ - public static func relativeToAbsolutePathManipulator(with path: XMLPath, absolutePath: URL = FileManager.default - .currentDirectoryPath.asURL) -> XMLPathManipulator { + public static func relativeToAbsolutePathManipulator( + with path: XMLPath, + absolutePath: URL + ) -> XMLPathManipulator { XMLPathManipulatorHolder(path: path) { _, element in if var elementValue = element.value { if elementValue.hasPrefix("../") || elementValue.hasPrefix("./") { diff --git a/CardSimulationTestKit/Sources/CardSimulationRunner/main.swift b/CardSimulationTestKit/Sources/CardSimulationRunner/main.swift index 026a74a..4f89046 100644 --- a/CardSimulationTestKit/Sources/CardSimulationRunner/main.swift +++ b/CardSimulationTestKit/Sources/CardSimulationRunner/main.swift @@ -16,7 +16,6 @@ import CardSimulationLoader import Foundation -import GemCommonsKit func main() throws { Logger.cardSimulationRunner.debug("Cmdline working directory: [\(FileManager.default.currentDirectoryPath)]") diff --git a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/Card/SimulatorCardChannelTest.swift b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/Card/SimulatorCardChannelTest.swift index c86a7ce..124a792 100644 --- a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/Card/SimulatorCardChannelTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/Card/SimulatorCardChannelTest.swift @@ -17,13 +17,12 @@ import CardReaderProviderApi @testable import CardSimulationCardReaderProvider import Foundation -import GemCommonsKit import Nimble import XCTest final class SimulatorCardChannelTest: XCTestCase { class MockSimulatorCard: CardType { - var atr: ATR = Data.empty + var atr: ATR = Data() var `protocol`: CardProtocol = .t1 func openBasicChannel() throws -> CardChannelType { diff --git a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/MockSimulationManager.swift b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/MockSimulationManager.swift index d3c5012..3b5acde 100644 --- a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/MockSimulationManager.swift +++ b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/MockSimulationManager.swift @@ -14,9 +14,9 @@ // limitations under the License. // +@testable import CardSimulationCardReaderProvider import CardSimulationLoader import Foundation -import GemCommonsKit class MockSimulationManager: SimulationManagerType { var delegates = WeakArray() diff --git a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/DataExtBerTLVTest.swift b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/DataExtBerTLVTest.swift index e2b6b7c..7b277a3 100644 --- a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/DataExtBerTLVTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/DataExtBerTLVTest.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import Nimble @testable import CardSimulationCardReaderProvider diff --git a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/TCPClientExtStreamingTest.swift b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/TCPClientExtStreamingTest.swift index 1abd61f..6553799 100644 --- a/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/TCPClientExtStreamingTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationCardReaderProviderTests/internal/TCPClientExtStreamingTest.swift @@ -15,7 +15,6 @@ // @testable import CardSimulationCardReaderProvider -import GemCommonsKit import Nimble import SwiftSocket import XCTest diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/Logger.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/Logger.swift new file mode 100644 index 0000000..22c66bf --- /dev/null +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/Logger.swift @@ -0,0 +1,24 @@ +// +// 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 OSLog + +extension Logger { + static let cardSimulationLoaderTests = Logger( + subsystem: "de.gematik.ti.ohcapp4ios", + category: "cardSimulationLoaderTests" + ) +} diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationManagerTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationManagerTest.swift index 0e96f55..9026e97 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationManagerTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationManagerTest.swift @@ -15,8 +15,8 @@ // @testable import CardSimulationLoader -import GemCommonsKit import Nimble +import OSLog import XCTest final class SimulationManagerTest: XCTestCase { @@ -130,7 +130,7 @@ final class SimulationManagerTest: XCTestCase { expect(weakDelegate?.didCallEnded ?? false).to(beFalse()) expect(weakDelegate).to(beNil()) } catch { - ALog("Exception thrown in test-case [\(error)]") + Logger.cardSimulationLoaderTests.fault("Exception thrown in test-case [\(error)]") #if os(macOS) || os(Linux) Nimble.fail("Failed with error \(error)") #else @@ -168,7 +168,7 @@ final class SimulationManagerTest: XCTestCase { expect(delegate.didCallEnded).to(beTrue()) } catch { - ALog("Exception thrown in test-case [\(error)]") + Logger.cardSimulationLoaderTests.fault("Exception thrown in test-case [\(error)]") #if os(macOS) || os(Linux) Nimble.fail("Failed with error \(error)") #else diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationRunnerTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationRunnerTest.swift index 96f5fee..e93491d 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationRunnerTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/SimulationRunnerTest.swift @@ -15,7 +15,6 @@ // @testable import CardSimulationLoader -import GemCommonsKit import Nimble import OSLog import XCTest @@ -43,7 +42,7 @@ final class SimulationRunnerTest: XCTestCase { ) .get() } catch { - ALog("Error while loading dependencies: \(error)") + Logger.cardSimulationLoader.fault("Error while loading dependencies: \(error)") } } @@ -52,7 +51,7 @@ final class SimulationRunnerTest: XCTestCase { do { try FileManager.default.removeItem(at: simTempPath) } catch { - ALog("Error while cleaning up test-case. \(String(describing: error))") + Logger.cardSimulationLoader.fault("Error while cleaning up test-case. \(String(describing: error))") } super.tearDown() } diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/internal/SimulationManagerExtInternalTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/internal/SimulationManagerExtInternalTest.swift index 9dfcd3b..19743e8 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/internal/SimulationManagerExtInternalTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/internal/SimulationManagerExtInternalTest.swift @@ -17,8 +17,8 @@ import AEXML @testable import CardSimulationLoader import Foundation -import GemCommonsKit import Nimble +import OSLog import XCTest final class SimulationManagerExtInternalTest: XCTestCase { @@ -52,7 +52,7 @@ final class SimulationManagerExtInternalTest: XCTestCase { expect(dependencyInfo.simulatorExists).to(beTrue()) try FileManager.default.removeItem(at: simPath) } catch { - ALog("Test-case failed with exception: [\(error)]") + Logger.cardSimulationLoaderTests.fault("Test-case failed with exception: [\(error)]") Nimble.fail("Failed with error \(error)") } } @@ -91,7 +91,7 @@ final class SimulationManagerExtInternalTest: XCTestCase { // cleanup try FileManager.default.removeItem(at: outputPath) } catch { - ALog("Test-case failed with exception: [\(error)]") + Logger.cardSimulationLoaderTests.fault("Test-case failed with exception: [\(error)]") Nimble.fail("Failed with error \(error)") } } diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/AEXMLDocumentExtXMLManipulationTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/AEXMLDocumentExtXMLManipulationTest.swift index d2c1a31..ddf8abc 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/AEXMLDocumentExtXMLManipulationTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/AEXMLDocumentExtXMLManipulationTest.swift @@ -16,8 +16,8 @@ import AEXML @testable import CardSimulationLoader -import GemCommonsKit import Nimble +import OSLog import XCTest final class AEXMLDocumentExtXMLManipulationTest: XCTestCase { @@ -43,7 +43,7 @@ final class AEXMLDocumentExtXMLManipulationTest: XCTestCase { expect(configElement?.value).to(equal("changed_../images/HBAG2_80276883110000017289_gema5.xml")) expect(xmlResult.root["ioConfiguration"]["port"].value).to(equal("0")) } catch { - ALog("Test-case failed: [\(error)]") + Logger.cardSimulationLoaderTests.fault("Test-case failed: [\(error)]") Nimble.fail("Failed with error \(error)") } } diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/URLExtConfigurationFileProcessorTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/URLExtConfigurationFileProcessorTest.swift index cab22a0..28f44b3 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/URLExtConfigurationFileProcessorTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/URLExtConfigurationFileProcessorTest.swift @@ -16,7 +16,6 @@ import AEXML @testable import CardSimulationLoader -import GemCommonsKit import Nimble import XCTest diff --git a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/XMLPathTest.swift b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/XMLPathTest.swift index 4f77a4d..ef26efe 100644 --- a/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/XMLPathTest.swift +++ b/CardSimulationTestKit/Tests/CardSimulationLoaderTests/xml/XMLPathTest.swift @@ -16,8 +16,8 @@ import AEXML @testable import CardSimulationLoader -import GemCommonsKit import Nimble +import OSLog import XCTest final class XMLPathTest: XCTestCase { @@ -85,7 +85,7 @@ final class XMLPathTest: XCTestCase { expect(elementAfter?.xml).to(equal(element.xml)) expect(elementAfter?.xml).toNot(equal(elementBefore?.xml)) } catch { - ALog("Test-case failed with exception: [\(error)]") + Logger.cardSimulationLoaderTests.fault("Test-case failed with exception: [\(error)]") Nimble.fail("Failed with error \(error)") } } diff --git a/Cartfile b/Cartfile index de8f039..63406d6 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,2 @@ -github "gematik/ref-GemCommonsKit" ~> 1.3 github "gematik/ASN1Kit" ~> 1.1 github "gematik/OpenSSL-Swift" ~> 4.0 \ No newline at end of file diff --git a/Cartfile.resolved b/Cartfile.resolved index 2d3badc..a694178 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,4 @@ github "Quick/Nimble" "v11.2.2" github "gematik/ASN1Kit" "1.3.1" github "gematik/OpenSSL-Swift" "4.2.0" -github "gematik/ref-GemCommonsKit" "1.3.0" github "swiftsocket/SwiftSocket" "2e6ba27140a29fae8a6331ba4463312e0c71a6b0" diff --git a/Gemfile.lock b/Gemfile.lock index bfe840d..214cdbc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,11 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.6) + CFPropertyList (3.0.7) + base64 + nkf rexml - activesupport (7.1.2) + activesupport (7.1.3.4) base64 bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) @@ -13,40 +15,40 @@ GEM minitest (>= 5.1) mutex_m tzinfo (~> 2.0) - addressable (2.8.5) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - artifactory (3.0.15) - asciidoctor (2.0.20) - asciidoctor-reducer (1.0.5) + artifactory (3.0.17) + asciidoctor (2.0.23) + asciidoctor-reducer (1.0.6) asciidoctor (~> 2.0) atomos (0.1.3) aws-eventstream (1.3.0) - aws-partitions (1.862.0) - aws-sdk-core (3.190.0) + aws-partitions (1.962.0) + aws-sdk-core (3.201.4) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) aws-sigv4 (~> 1.8) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.74.0) - aws-sdk-core (~> 3, >= 3.188.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.141.0) - aws-sdk-core (~> 3, >= 3.189.0) + aws-sdk-kms (1.88.0) + aws-sdk-core (~> 3, >= 3.201.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.157.0) + aws-sdk-core (~> 3, >= 3.201.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.8) - aws-sigv4 (1.8.0) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.9.1) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) base64 (0.2.0) - bigdecimal (3.1.4) + bigdecimal (3.1.8) claide (1.0.3) - cocoapods (1.14.3) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) @@ -61,7 +63,7 @@ GEM nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -84,20 +86,19 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.2) + concurrent-ruby (1.3.3) connection_pool (2.4.1) declarative (0.0.20) digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.6.20231109) + domain_name (0.6.20240107) dotenv (2.8.1) - drb (2.2.0) - ruby2_keywords + drb (2.2.1) emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.105.0) + excon (0.111.0) faraday (1.10.3) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) @@ -119,22 +120,22 @@ GEM faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) faraday-retry (1.0.3) faraday_middleware (1.2.0) faraday (~> 1.0) - fastimage (2.2.7) - fastlane (2.217.0) + fastimage (2.3.1) + fastlane (2.222.0) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) - colored + colored (~> 1.2) commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) @@ -146,6 +147,7 @@ GEM gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) google-cloud-storage (~> 1.31) highline (~> 2.0) http-cookie (~> 1.0.5) @@ -154,10 +156,10 @@ GEM mini_magick (>= 4.9.4, < 5.0.0) multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) - optparse (~> 0.1.1) + optparse (>= 0.1.1, < 1.0.0) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) + security (= 0.1.5) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) terminal-table (~> 3) @@ -166,14 +168,14 @@ GEM word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - ffi (1.16.3) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - google-apis-androidpublisher_v3 (0.53.0) + google-apis-androidpublisher_v3 (0.54.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.2) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -181,24 +183,23 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick google-apis-iamcredentials_v1 (0.17.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.29.0) + google-apis-storage_v1 (0.31.0) google-apis-core (>= 0.11.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-cloud-core (1.7.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.1) - google-cloud-storage (1.45.0) + google-cloud-errors (1.4.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.29.0) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) @@ -209,59 +210,62 @@ GEM os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.6) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.1) + i18n (1.14.5) concurrent-ruby (~> 1.0) - jazzy (0.14.4) + jazzy (0.15.1) cocoapods (~> 1.5) mustache (~> 1.1) open4 (~> 1.3) redcarpet (~> 3.4) - rexml (~> 3.2) + rexml (>= 3.2.7, < 4.0) rouge (>= 2.0.6, < 5.0) sassc (~> 2.1) sqlite3 (~> 1.3) xcinvoke (~> 0.3.0) jmespath (1.6.2) - json (2.7.0) - jwt (2.7.1) + json (2.7.2) + jwt (2.8.2) + base64 liferaft (0.0.6) - mini_magick (4.12.0) + mini_magick (4.13.2) mini_mime (1.1.5) - mini_portile2 (2.8.5) - minitest (5.20.0) + mini_portile2 (2.8.7) + minitest (5.24.1) molinillo (0.8.0) multi_json (1.15.0) - multipart-post (2.3.0) + multipart-post (2.4.1) mustache (1.1.1) mutex_m (0.2.0) nanaimo (0.3.0) nap (1.1.0) naturally (2.2.1) netrc (0.11.0) + nkf (0.2.0) open4 (1.3.4) - optparse (0.1.1) + optparse (0.5.0) os (1.1.4) - plist (3.7.0) + plist (3.7.1) public_suffix (4.0.7) - rake (13.1.0) + rake (13.2.1) redcarpet (3.6.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.6) + rexml (3.3.4) + strscan rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) rubyzip (2.3.2) sassc (2.4.0) ffi (~> 1.9) - security (0.1.3) - signet (0.18.0) + security (0.1.5) + signet (0.19.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) @@ -269,14 +273,15 @@ GEM simctl (1.6.10) CFPropertyList naturally - sqlite3 (1.6.9) + sqlite3 (1.7.3) mini_portile2 (~> 2.8.0) + strscan (3.1.0) terminal-notifier (2.0.0) terminal-table (3.0.2) unicode-display_width (>= 1.1.1, < 3) trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.8.1) + tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) typhoeus (1.4.1) @@ -285,20 +290,19 @@ GEM concurrent-ruby (~> 1.0) uber (0.1.0) unicode-display_width (2.5.0) - webrick (1.8.1) word_wrap (1.0.0) xcinvoke (0.3.0) liferaft (~> 0.0.6) xcode-install (2.6.8) claide (>= 0.9.1, < 1.1.0) fastlane (>= 2.1.0, < 3.0.0) - xcodeproj (1.23.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-travis-formatter (1.0.1) diff --git a/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalResource.swift b/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalResource.swift index 955bcbe..927c850 100644 --- a/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalResource.swift +++ b/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalResource.swift @@ -19,7 +19,6 @@ import CardReaderProviderApi import CardSimulationCardReaderProvider import CardSimulationLoader import Foundation -import GemCommonsKit import OSLog /// Wrapper around a resource that holds the configuration for a G2-Kartensimulation Runner @@ -147,7 +146,7 @@ class DisconnectedCard: CardType { let `protocol`: CardProtocol init() { - atr = Data.empty + atr = Data() self.protocol = CardProtocol(rawValue: 0) } @@ -171,3 +170,60 @@ class DisconnectedCard: CardType { "DisconnectedCard" } } + +class BlockingVar { + private enum State: Int { + case empty = 0 + case fulfilled + } + + private var _value: T! + private let lock: NSConditionLock + + /// Initialize w/o value + init() { + lock = NSConditionLock(condition: State.empty.rawValue) + } + + /// Initialize w/ value value + init(_ value: T) { + _value = value + lock = NSConditionLock(condition: State.fulfilled.rawValue) + } + + /// Access value + var value: T { + get { + if Thread.isMainThread { + // wait for self.isFulfilled + while !isFulfilled { + Logger.integrationTest.fault("Caution: trying to obtain a lock on the main thread") + RunLoop.current.run(mode: .default, before: Date(timeIntervalSinceNow: 0.001)) + } + } + /// Obtain a lock when the condition is fulfilled. This may seem counter intuitive since, + /// we want to wait/lock while empty and continue when fulfilled. + /// So what lock(whenCondition:) actually does, is waiting/blocking execution until the lock + /// unlocks with fulfilled. Then and only then the lock can be obtained and execution resumed. + lock.lock(whenCondition: State.fulfilled.rawValue) + defer { + /// Of course we unlock the lock so consecutive calls make it through as well. + lock.unlock(withCondition: State.fulfilled.rawValue) + } + return _value + } + set { + /// Obtain a lock before writing the value + lock.lock() + _value = newValue + /// Unlock stating that we have fulfilled the value + lock.unlock(withCondition: State.fulfilled.rawValue) + } + } + + /// Non-blocking check whether self has been fulfilled or not + /// - Returns: `true` on .fulfilled `false` when .empty + var isFulfilled: Bool { + lock.condition == State.fulfilled.rawValue + } +} diff --git a/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalTestCase.swift b/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalTestCase.swift index 99aef2b..3fe28d0 100644 --- a/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalTestCase.swift +++ b/IntegrationTests/CardSimulationTerminalTestCase/CardSimulationTerminalTestCase.swift @@ -17,8 +17,8 @@ import CardReaderProviderApi import CardSimulationLoader import Foundation -import GemCommonsKit import HealthCardAccess +import OSLog import XCTest /// 'Abstract' `XCTestCase` that prepares and sets up a G2-Kartensimulator (through `CardSimulationLoader`) @@ -107,7 +107,7 @@ class CardSimulationTerminalTestCase: XCTestCase { do { try createHealthCard() } catch { - ALog("Could not create HealthCard: \(error)") + Logger.integrationTest.fault("Could not create HealthCard: \(error)") } } @@ -115,7 +115,7 @@ class CardSimulationTerminalTestCase: XCTestCase { do { try disconnectCard() } catch { - ALog("Could not disconnect card: \(error)") + Logger.integrationTest.fault("Could not disconnect card: \(error)") } super.tearDown() } diff --git a/IntegrationTests/HealthCardAccess/PublisherIntegrationTest.swift b/IntegrationTests/HealthCardAccess/PublisherIntegrationTest.swift index 969b9ce..45ddd20 100644 --- a/IntegrationTests/HealthCardAccess/PublisherIntegrationTest.swift +++ b/IntegrationTests/HealthCardAccess/PublisherIntegrationTest.swift @@ -17,7 +17,6 @@ import CardReaderProviderApi import Combine import Foundation -import GemCommonsKit @testable import HealthCardAccess import Nimble import OSLog diff --git a/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift b/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift index dda87e6..9720c45 100644 --- a/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift +++ b/IntegrationTests/HealthCardControl/AuthenticateChallengeE256Test.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift b/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift index b049cd9..4f36f02 100644 --- a/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift +++ b/IntegrationTests/HealthCardControl/AuthenticateChallengeR2048Test.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift b/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift index cbe02ea..0468f7d 100644 --- a/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/CardChannelTypeExtVersionIntegrationTest.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift b/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift index d779959..f291e3a 100644 --- a/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/KeyAgreementIntegrationTest.swift @@ -16,7 +16,6 @@ import CardReaderProviderApi import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift b/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift index 5c62349..075a6d4 100644 --- a/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/OpenSecureSessionIntegrationTest.swift @@ -17,7 +17,6 @@ import CardReaderProviderApi import CardSimulationCardReaderProvider import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift b/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift index c45624d..1799b5d 100644 --- a/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift +++ b/IntegrationTests/HealthCardControl/ReadAutCertificateE256Test.swift @@ -15,10 +15,10 @@ // import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble +import OSLog import Util import XCTest @@ -36,7 +36,7 @@ final class ReadAutCertificateE256Test: CardSimulationTerminalTestCase { do { expectedCertificate = try Data(contentsOf: path) } catch { - ALog("Could not read certificate file: \(path)\nError: \(error)") + Logger.integrationTest.fault("Could not read certificate file: \(path)\nError: \(error)") } } diff --git a/IntegrationTests/HealthCardControl/ReadAutCertificateR2048Test.swift b/IntegrationTests/HealthCardControl/ReadAutCertificateR2048Test.swift index 6ebb8e2..2db3971 100644 --- a/IntegrationTests/HealthCardControl/ReadAutCertificateR2048Test.swift +++ b/IntegrationTests/HealthCardControl/ReadAutCertificateR2048Test.swift @@ -15,10 +15,10 @@ // import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble +import OSLog import XCTest final class ReadAutCertificateR2048Test: CardSimulationTerminalTestCase { @@ -32,7 +32,7 @@ final class ReadAutCertificateR2048Test: CardSimulationTerminalTestCase { do { expectedCertificate = try Data(contentsOf: path) } catch { - ALog("Could not read certificate file: \(path)\nError: \(error)") + Logger.integrationTest.fault("Could not read certificate file: \(path)\nError: \(error)") } } diff --git a/IntegrationTests/HealthCardControl/ReadFileIntegrationTest.swift b/IntegrationTests/HealthCardControl/ReadFileIntegrationTest.swift index 919f974..41b9c78 100644 --- a/IntegrationTests/HealthCardControl/ReadFileIntegrationTest.swift +++ b/IntegrationTests/HealthCardControl/ReadFileIntegrationTest.swift @@ -17,10 +17,10 @@ import CardReaderProviderApi import CardSimulationCardReaderProvider import Foundation -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble +import OSLog import XCTest final class ReadFileIntegrationTest: CardSimulationTerminalTestCase { @@ -44,7 +44,7 @@ final class ReadFileIntegrationTest: CardSimulationTerminalTestCase { do { expectedCertificate = try Data(contentsOf: path) } catch { - ALog("Could not read certificate file: \(path)\nError: \(error)") + Logger.integrationTest.fault("Could not read certificate file: \(path)\nError: \(error)") } do { @@ -52,7 +52,7 @@ final class ReadFileIntegrationTest: CardSimulationTerminalTestCase { .publisher(for: Self.healthCard) .test() } catch { - ALog("Could not execute select root command while setup\nError: \(error)") + Logger.integrationTest.fault("Could not execute select root command while setup\nError: \(error)") } } diff --git a/IntegrationTests/ResourceLoader.swift b/IntegrationTests/ResourceLoader.swift new file mode 100644 index 0000000..30e0cec --- /dev/null +++ b/IntegrationTests/ResourceLoader.swift @@ -0,0 +1,108 @@ +// 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/IntegrationTests/project.yml b/IntegrationTests/project.yml index 2244476..c02db51 100644 --- a/IntegrationTests/project.yml +++ b/IntegrationTests/project.yml @@ -42,8 +42,6 @@ targets: - target: AEXMLExt - package: StreamReader - framework: Carthage/Build/SwiftSocket.xcframework - - package: GemCommonsKit - product: GemCommonsKit # CardSimulationTestKit @@ -58,15 +56,12 @@ targets: settings: base: BUILD_LIBRARY_FOR_DISTRIBUTION: NO + SWIFT_OBJC_BRIDGING_HEADER: CardSimulationTestKit/Sources/CardSimulationLoader/exception/include/ExceptionCatcher.h dependencies: - package: AEXML - target: AEXMLExt embed: true - package: StreamReader - - package: GemCommonsKit - product: GemCommonsKit - - package: GemCommonsKit - product: ObjCCommonsKit transitivelyLinkDependencies: true scheme: testTargets: @@ -114,8 +109,6 @@ targets: - target: CardSimulationLoader - package: AEXML - package: StreamReader - - package: GemCommonsKit - product: GemCommonsKit CardSimulationCardReaderProvider: type: framework platform: macOS @@ -147,8 +140,6 @@ targets: - package: AEXML - target: AEXMLExt - target: CardSimulationLoader - - package: GemCommonsKit - product: GemCommonsKit - framework: Carthage/Build/Nimble.xcframework gatherCoverageData: true AEXMLExtTests: @@ -175,6 +166,4 @@ targets: - target: CardSimulationCardReaderProvider - target: AEXMLExt - framework: Carthage/Build/Nimble.xcframework - - package: GemCommonsKit - product: GemCommonsKit gatherCoverageData: true \ No newline at end of file diff --git a/Package.resolved b/Package.resolved index 886e99a..2a420e6 100644 --- a/Package.resolved +++ b/Package.resolved @@ -54,15 +54,6 @@ "version" : "4.2.0" } }, - { - "identity" : "ref-gemcommonskit", - "kind" : "remoteSourceControl", - "location" : "https://github.com/gematik/ref-GemCommonsKit", - "state" : { - "revision" : "e19c2961ad48cf8897b679bde109988cf96fbb59", - "version" : "1.3.0" - } - }, { "identity" : "swift-docc-plugin", "kind" : "remoteSourceControl", diff --git a/Package.swift b/Package.swift index 88ebff1..ad23d71 100644 --- a/Package.swift +++ b/Package.swift @@ -28,7 +28,6 @@ let package = Package( 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/gematik/ref-GemCommonsKit", from: "1.3.0"), .package(url: "https://github.com/apple/swift-docc-plugin", from: "1.3.0"), ], targets: [ @@ -38,7 +37,6 @@ let package = Package( "HealthCardControl", "HealthCardAccess", "Helper", - .product(name: "GemCommonsKit", package: "ref-GemCommonsKit") ] ), .target( @@ -59,7 +57,7 @@ let package = Package( ), .target( name: "CardReaderProviderApi", - dependencies: ["Helper", .product(name: "GemCommonsKit", package: "ref-GemCommonsKit")] + dependencies: ["Helper",] ), .target( name: "Helper" diff --git a/ReleaseNotes.md b/ReleaseNotes.md index 261f7b1..f3d6201 100644 --- a/ReleaseNotes.md +++ b/ReleaseNotes.md @@ -1,3 +1,8 @@ +# 5.10.0 + +- Remove dependency on GemCommonsKit +- Remove dependency on DataKit + # 5.9.0 - Publish CardSimulator loading/running code for running IntegrationTests (CardSimulation itself cannot be public though) diff --git a/Sources/CardReaderAccess/CardReaderControllerManager.swift b/Sources/CardReaderAccess/CardReaderControllerManager.swift index f062836..a35af7c 100644 --- a/Sources/CardReaderAccess/CardReaderControllerManager.swift +++ b/Sources/CardReaderAccess/CardReaderControllerManager.swift @@ -16,7 +16,6 @@ import CardReaderProviderApi import Foundation -import GemCommonsKit /// The protocol represents the behavior for a ServiceLoader that provides `CardReaderControllerType`s public protocol CardReaderControllerManagerType: AnyObject { diff --git a/Sources/CardReaderProviderApi/Card/CardType.swift b/Sources/CardReaderProviderApi/Card/CardType.swift index 0332521..dbc2078 100644 --- a/Sources/CardReaderProviderApi/Card/CardType.swift +++ b/Sources/CardReaderProviderApi/Card/CardType.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit /// Answer-to-reset is of Type Data public typealias ATR = Data @@ -91,7 +90,7 @@ public protocol CardType: CustomStringConvertible { extension CardType { /// Default implementation returns empty data object. public func transmitControl(command _: Int, data _: Data) throws -> Data { - Data.empty + Data() } /// Default implementation returns nil. diff --git a/Sources/CardReaderProviderApi/Command/APDU.swift b/Sources/CardReaderProviderApi/Command/APDU.swift index 29c994e..6cf6876 100644 --- a/Sources/CardReaderProviderApi/Command/APDU.swift +++ b/Sources/CardReaderProviderApi/Command/APDU.swift @@ -64,7 +64,7 @@ public class APDU { } /// Success response [0x9000] - public static let OK = try! Response(apdu: [0x90, 0x0].data) + public static let OK = try! Response(apdu: Data([0x90, 0x0])) // swiftlint:disable:previous identifier_name force_try } diff --git a/Sources/HealthCardAccess/CardObjects/ApplicationIdentifier.swift b/Sources/HealthCardAccess/CardObjects/ApplicationIdentifier.swift index 91765de..df9fa74 100644 --- a/Sources/HealthCardAccess/CardObjects/ApplicationIdentifier.swift +++ b/Sources/HealthCardAccess/CardObjects/ApplicationIdentifier.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit /// ApplicationIdentifier representation to prevent (accidental) misuse /// E.g. using any 'random' String as function parameter where a AID is expected diff --git a/Sources/HealthCardAccess/CardObjects/CardObjectIdentifierType.swift b/Sources/HealthCardAccess/CardObjects/CardObjectIdentifierType.swift index 3a207ba..dec551d 100644 --- a/Sources/HealthCardAccess/CardObjects/CardObjectIdentifierType.swift +++ b/Sources/HealthCardAccess/CardObjects/CardObjectIdentifierType.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit public protocol CardObjectIdentifierType: Equatable, ExpressibleByStringLiteral { /// The representation for the Card Object Identifier (E.g. AID, FID) diff --git a/Sources/HealthCardAccess/CardObjects/FileIdentifier.swift b/Sources/HealthCardAccess/CardObjects/FileIdentifier.swift index b58d9b6..a5da1d2 100644 --- a/Sources/HealthCardAccess/CardObjects/FileIdentifier.swift +++ b/Sources/HealthCardAccess/CardObjects/FileIdentifier.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit /// File Identifier - gemSpec_COS 8.1.1 #N006.700, N006.900 public struct FileIdentifier: CardObjectIdentifierType { diff --git a/Sources/HealthCardAccess/CardObjects/ShortFileIdentifier.swift b/Sources/HealthCardAccess/CardObjects/ShortFileIdentifier.swift index eda1e2c..50f3b4b 100644 --- a/Sources/HealthCardAccess/CardObjects/ShortFileIdentifier.swift +++ b/Sources/HealthCardAccess/CardObjects/ShortFileIdentifier.swift @@ -15,7 +15,6 @@ // import Foundation -import GemCommonsKit /// Short File Identifier - gemSpec_COS#N007.000 public struct ShortFileIdentifier: CardObjectIdentifierType { diff --git a/Sources/HealthCardAccess/Commands/HealthCardCommand+ManageSE.swift b/Sources/HealthCardAccess/Commands/HealthCardCommand+ManageSE.swift index cd40691..81fe490 100644 --- a/Sources/HealthCardAccess/Commands/HealthCardCommand+ManageSE.swift +++ b/Sources/HealthCardAccess/Commands/HealthCardCommand+ManageSE.swift @@ -17,7 +17,6 @@ import ASN1Kit import CardReaderProviderApi import Foundation -import GemCommonsKit extension HealthCardCommand { /// Use case Manage Security Environment - gemSpec_COS#14.9.9 diff --git a/Sources/HealthCardAccess/Commands/HealthCardCommand+Misc.swift b/Sources/HealthCardAccess/Commands/HealthCardCommand+Misc.swift index 312cadc..530d193 100644 --- a/Sources/HealthCardAccess/Commands/HealthCardCommand+Misc.swift +++ b/Sources/HealthCardAccess/Commands/HealthCardCommand+Misc.swift @@ -17,7 +17,6 @@ import ASN1Kit import CardReaderProviderApi import Foundation -import GemCommonsKit extension HealthCardCommand { /// Builder representing Miscellaneous Commands in gemSpec_COS#14.9 diff --git a/Sources/HealthCardControl/Operations/CardChannelType+CardAID.swift b/Sources/HealthCardControl/Operations/CardChannelType+CardAID.swift index cce41ce..20101ee 100644 --- a/Sources/HealthCardControl/Operations/CardChannelType+CardAID.swift +++ b/Sources/HealthCardControl/Operations/CardChannelType+CardAID.swift @@ -57,7 +57,7 @@ extension CardChannelType { $0.publisher(for: channel) } .tryMap { - let fcp = try FileControlParameter.parse(data: $0.data ?? Data.empty) + let fcp = try FileControlParameter.parse(data: $0.data ?? Data()) guard let aid = fcp.applicationIdentifier else { throw HealthCard.Error.unknownCardType(aid: nil) } diff --git a/Sources/HealthCardControl/Operations/CardChannelType+Version.swift b/Sources/HealthCardControl/Operations/CardChannelType+Version.swift index 03b242b..6388318 100644 --- a/Sources/HealthCardControl/Operations/CardChannelType+Version.swift +++ b/Sources/HealthCardControl/Operations/CardChannelType+Version.swift @@ -90,7 +90,7 @@ extension CardChannelType { $0.publisher(for: channel, writeTimeout: writeTimeout, readTimeout: readTimeout) } .tryMap { response in - let cardVersion2 = try CardVersion2(data: response.data ?? Data.empty) + let cardVersion2 = try CardVersion2(data: response.data ?? Data()) return try HealthCardPropertyType.from(cardAid: cardAid, cardVersion2: cardVersion2) } } @@ -140,7 +140,7 @@ extension CardChannelType { readTimeout: readTimeout ) - let cardVersion2 = try CardVersion2(data: readResponse.data ?? Data.empty) + let cardVersion2 = try CardVersion2(data: readResponse.data ?? Data()) return try HealthCardPropertyType.from(cardAid: determinedCardAid, cardVersion2: cardVersion2) } } diff --git a/Sources/HealthCardControl/SecureMessaging/CardType+SecureMessaging.swift b/Sources/HealthCardControl/SecureMessaging/CardType+SecureMessaging.swift index ee60a9b..220e973 100644 --- a/Sources/HealthCardControl/SecureMessaging/CardType+SecureMessaging.swift +++ b/Sources/HealthCardControl/SecureMessaging/CardType+SecureMessaging.swift @@ -17,7 +17,6 @@ import CardReaderProviderApi import Combine import Foundation -import GemCommonsKit import HealthCardAccess import Helper diff --git a/Sources/HealthCardControl/SecureMessaging/KeyAgreement.swift b/Sources/HealthCardControl/SecureMessaging/KeyAgreement.swift index 5be9b84..4d5b2c4 100644 --- a/Sources/HealthCardControl/SecureMessaging/KeyAgreement.swift +++ b/Sources/HealthCardControl/SecureMessaging/KeyAgreement.swift @@ -19,7 +19,6 @@ import ASN1Kit import CardReaderProviderApi import Combine import Foundation -import GemCommonsKit import HealthCardAccess import OpenSSL import OSLog diff --git a/Sources/HealthCardControl/SecureMessaging/SecureCardChannel.swift b/Sources/HealthCardControl/SecureMessaging/SecureCardChannel.swift index c6d8027..e92f889 100644 --- a/Sources/HealthCardControl/SecureMessaging/SecureCardChannel.swift +++ b/Sources/HealthCardControl/SecureMessaging/SecureCardChannel.swift @@ -16,7 +16,6 @@ import CardReaderProviderApi import Foundation -import GemCommonsKit import HealthCardAccess import Helper import OSLog diff --git a/Sources/NFCCardReaderProvider/Card/NFCCard.swift b/Sources/NFCCardReaderProvider/Card/NFCCard.swift index a608e5d..8ca2a67 100644 --- a/Sources/NFCCardReaderProvider/Card/NFCCard.swift +++ b/Sources/NFCCardReaderProvider/Card/NFCCard.swift @@ -19,7 +19,6 @@ import CardReaderProviderApi import CoreNFC import Foundation -import GemCommonsKit import HealthCardAccess import OSLog @@ -99,7 +98,7 @@ public class NFCCard: CardType { public func initialApplicationIdentifier() throws -> Data? { guard let initialSelectedAID = tag?.initialSelectedAID else { - ALog("NFC tag could not deliver initialSelectedAID when expected") + Logger.nfcCardReaderProvider.fault("NFC tag could not deliver initialSelectedAID when expected") return nil } return try Data(hex: initialSelectedAID) @@ -116,7 +115,7 @@ public class NFCCard: CardType { do { try disconnect(reset: false) } catch { - ALog("Error while disconnecting: \(error)") + Logger.nfcCardReaderProvider.fault("Error while disconnecting: \(error)") } } diff --git a/Sources/NFCCardReaderProvider/Card/NFCCardChannel.swift b/Sources/NFCCardReaderProvider/Card/NFCCardChannel.swift index 4850299..6a8bd76 100644 --- a/Sources/NFCCardReaderProvider/Card/NFCCardChannel.swift +++ b/Sources/NFCCardReaderProvider/Card/NFCCardChannel.swift @@ -19,7 +19,6 @@ import CardReaderProviderApi import CoreNFC import Foundation -import GemCommonsKit import Helper import OSLog diff --git a/Sources/NFCCardReaderProvider/NFCHealthCardSession.swift b/Sources/NFCCardReaderProvider/NFCHealthCardSession.swift index c3c9fdb..aaf8864 100644 --- a/Sources/NFCCardReaderProvider/NFCHealthCardSession.swift +++ b/Sources/NFCCardReaderProvider/NFCHealthCardSession.swift @@ -20,7 +20,6 @@ import CardReaderProviderApi import Combine import CoreNFC import Foundation -import GemCommonsKit import HealthCardAccess import HealthCardControl import OSLog diff --git a/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift b/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift index ed9b4ac..14d339e 100644 --- a/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift +++ b/Sources/NFCCardReaderProvider/Reader/NFCTagReaderSession+Publisher.swift @@ -20,7 +20,6 @@ import CardReaderProviderApi import Combine import CoreNFC import Foundation -import GemCommonsKit import OSLog /// Abstraction to the NFCTagReaderSession to update the alertMessage that is being displayed to the user. @@ -268,3 +267,69 @@ extension NFCTagReaderSession.Publisher { } #endif + +@propertyWrapper +struct Synchronized { + private let backing: SynchronizedVar + + /// Initialize a Synchronized wrapper + /// + /// - Parameter backing: the initial value + init(wrappedValue backing: T) { + self.backing = SynchronizedVar(backing) + } + + /// Get/Set the backed value + var wrappedValue: T { + get { + backing.value + } + set { + backing.set { _ in + newValue + } + } + } + + /// Projected self + var projectedValue: Synchronized { + get { + self + } + mutating set { + self = newValue + } + } +} + +class SynchronizedVar { + private var _value: T + private let mutex = NSRecursiveLock() + + /// Canonical constructor + init(_ value: T) { + _value = value + } + + /** + Get/Set the value for this SynchronizedVar in a + thread-safe (blocking) manner + */ + var value: T { + mutex.lock() + defer { + mutex.unlock() + } + return _value + } + + /// Set a new value in a transaction to make sure there is no potential 'gap' between get and consecutive set + /// + /// - Parameter block: the transaction that gets the oldValue and must return the newValue that will be stored + /// in the backing value. + func set(transaction block: @escaping (T) -> T) { + mutex.lock() + _value = block(_value) + mutex.unlock() + } +} diff --git a/Sources/NFCDemo/NFC/NFCLoginController.swift b/Sources/NFCDemo/NFC/NFCLoginController.swift index c0e557e..e256457 100644 --- a/Sources/NFCDemo/NFC/NFCLoginController.swift +++ b/Sources/NFCDemo/NFC/NFCLoginController.swift @@ -18,7 +18,6 @@ import CardReaderProviderApi import Combine import CoreNFC import Foundation -import GemCommonsKit import HealthCardAccess import HealthCardControl import Helper diff --git a/Tests/CardReaderProviderApiTests/Command/APDUCommandTest.swift b/Tests/CardReaderProviderApiTests/Command/APDUCommandTest.swift index 3fa5c53..2b36443 100644 --- a/Tests/CardReaderProviderApiTests/Command/APDUCommandTest.swift +++ b/Tests/CardReaderProviderApiTests/Command/APDUCommandTest.swift @@ -43,7 +43,7 @@ final class APDUCommandTest: XCTestCase { expect(command.ne).to(beNil()) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4]))) } func testCommandAPDU_case2s() throws { @@ -58,7 +58,7 @@ final class APDUCommandTest: XCTestCase { expect(command.ne).to(equal(6)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4, 0x6].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4, 0x6]))) } func testCommandAPDU_case2s_max() throws { @@ -73,7 +73,7 @@ final class APDUCommandTest: XCTestCase { expect(command.ne).to(equal(256)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4, 0x00].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4, 0x00]))) } func testCommandAPDU_case3s() throws { @@ -91,7 +91,7 @@ final class APDUCommandTest: XCTestCase { expect(command.nc).to(equal(10)) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0xA] + data - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4s() throws { @@ -110,7 +110,7 @@ final class APDUCommandTest: XCTestCase { expect(command.nc).to(equal(10)) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0xA] + data + [0xC] - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4s_max() throws { @@ -128,7 +128,7 @@ final class APDUCommandTest: XCTestCase { expect(command.nc).to(equal(10)) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0xA] + data + [0x00] - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case2e() throws { @@ -143,7 +143,7 @@ final class APDUCommandTest: XCTestCase { expect(command.ne).to(equal(30000)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4, 0x00, 0x75, 0x30].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4, 0x00, 0x75, 0x30]))) } func testCommandAPDU_case2e_max() throws { @@ -158,7 +158,7 @@ final class APDUCommandTest: XCTestCase { expect(command.ne).to(equal(APDU.expectedLengthWildcardExtended)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4, 0x0, 0x0, 0x0]))) } func testCommandAPDU_case3e() throws { @@ -185,7 +185,7 @@ final class APDUCommandTest: XCTestCase { let lc2 = UInt8(size & 0xFF) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0x00, lc1, lc2] + data - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4e_ne_512() throws { @@ -209,7 +209,7 @@ final class APDUCommandTest: XCTestCase { let lc2 = UInt8(size) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0x00, lc1, lc2] + data + [0x2, 0x0] - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4e_big_data() throws { @@ -233,7 +233,7 @@ final class APDUCommandTest: XCTestCase { let lc2 = UInt8(size & 0xFF) let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0x00, lc1, lc2] + data + [0x1, 0x0] - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4e_small_data() throws { @@ -253,7 +253,7 @@ final class APDUCommandTest: XCTestCase { let lc2: UInt8 = 0xA let expectedCommandData = [0x1, 0x2, 0x3, 0x4, 0x00, lc1, lc2] + data + [0x2, 0x0] - expect(command.bytes).to(equal(expectedCommandData.data)) + expect(command.bytes).to(equal(Data(expectedCommandData))) } func testCommandAPDU_case4e_too_big_data() throws { diff --git a/Tests/CardReaderProviderApiTests/Command/APDUResponseTest.swift b/Tests/CardReaderProviderApiTests/Command/APDUResponseTest.swift index 5bc0c0b..a598890 100644 --- a/Tests/CardReaderProviderApiTests/Command/APDUResponseTest.swift +++ b/Tests/CardReaderProviderApiTests/Command/APDUResponseTest.swift @@ -20,31 +20,31 @@ import XCTest final class APDUResponseTest: XCTestCase { func testAPDUResponse_valid() throws { - let responseMessage = [0xFE, 0x12, 0x34, 0x90, 0x00].data + let responseMessage = Data([0xFE, 0x12, 0x34, 0x90, 0x00]) let response = try APDU.Response(apdu: responseMessage) expect(response.sw1).to(equal(0x90)) expect(response.sw2).to(equal(0x0)) expect(response.sw).to(equal(0x9000)) expect(response.nr).to(equal(3)) - let expectedData = [0xFE, 0x12, 0x34].data + let expectedData = Data([0xFE, 0x12, 0x34]) expect(response.data).to(equal(expectedData)) } func testAPDUResponse_valid_convenience_initializer() throws { - let responseBody = [0xFE, 0x12, 0x34].data + let responseBody = Data([0xFE, 0x12, 0x34]) let response = try APDU.Response(body: responseBody, sw1: 0x90, sw2: 0x0) expect(response.sw1).to(equal(0x90)) expect(response.sw2).to(equal(0x0)) expect(response.sw).to(equal(0x9000)) expect(response.nr).to(equal(3)) - let expectedData = [0xFE, 0x12, 0x34].data + let expectedData = Data([0xFE, 0x12, 0x34]) expect(response.data).to(equal(expectedData)) } func testAPDUResponse_ok() throws { - let responseMessage = [0x90, 0x00].data + let responseMessage = Data([0x90, 0x00]) let response = try APDU.Response(apdu: responseMessage) expect(response.sw1).to(equal(0x90)) @@ -56,23 +56,23 @@ final class APDUResponseTest: XCTestCase { } func testAPDUResponse_equality() throws { - let responseMessage = [0x01, 0x02, 0x90, 0x00].data + let responseMessage = Data([0x01, 0x02, 0x90, 0x00]) let response = try APDU.Response(apdu: responseMessage) - let responseMessage2 = [0x01, 0x02, 0x90, 0x00].data + let responseMessage2 = Data([0x01, 0x02, 0x90, 0x00]) let response2 = try APDU.Response(apdu: responseMessage2) - let responseMessage3 = [0x03, 0x02, 0x90, 0x00].data + let responseMessage3 = Data([0x03, 0x02, 0x90, 0x00]) let response3 = try APDU.Response(apdu: responseMessage3) expect(response == response2).to(beTrue()) expect(response == response3).to(beFalse()) } func testAPDUResponse_emptyData() { - expect(try APDU.Response(apdu: Data.empty)) - .to(throwError(APDU.Error.insufficientResponseData(data: Data.empty))) + expect(try APDU.Response(apdu: Data())) + .to(throwError(APDU.Error.insufficientResponseData(data: Data()))) } func testAPDUResponseException_insufficientResponseData() { - let responseData = [0x01].data + let responseData = Data([0x01]) expect { try APDU.Response(apdu: responseData) }.to(throwError { (error: APDU.Error) in diff --git a/Tests/CardReaderProviderApiTests/Command/CommandTypeExtLogicChannelTests.swift b/Tests/CardReaderProviderApiTests/Command/CommandTypeExtLogicChannelTests.swift index 1e664cd..6fd6459 100644 --- a/Tests/CardReaderProviderApiTests/Command/CommandTypeExtLogicChannelTests.swift +++ b/Tests/CardReaderProviderApiTests/Command/CommandTypeExtLogicChannelTests.swift @@ -32,7 +32,7 @@ class CommandTypeExtLogicChannelTests: XCTestCase { expect(command.ne).to(equal(256)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x1, 0x2, 0x3, 0x4, 0x00].data)) + expect(command.bytes).to(equal(Data([0x1, 0x2, 0x3, 0x4, 0x00]))) } func testCommandAPDU_toChannel4() throws { @@ -48,7 +48,7 @@ class CommandTypeExtLogicChannelTests: XCTestCase { expect(command.ne).to(equal(256)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x40, 0x2, 0x3, 0x4, 0x00].data)) + expect(command.bytes).to(equal(Data([0x40, 0x2, 0x3, 0x4, 0x00]))) } func testCommandAPDU_toChannel19() throws { @@ -64,7 +64,7 @@ class CommandTypeExtLogicChannelTests: XCTestCase { expect(command.ne).to(equal(256)) expect(command.nc).to(equal(0)) - expect(command.bytes).to(equal([0x4F, 0x2, 0x3, 0x4, 0x00].data)) + expect(command.bytes).to(equal(Data([0x4F, 0x2, 0x3, 0x4, 0x00]))) } func testCommandAPDU_toChannel20() throws { diff --git a/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift b/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift index 85c46b8..ca8bbf2 100644 --- a/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift +++ b/Tests/HealthCardAccessTests/CardObjects/FileControlParameterTest.swift @@ -14,7 +14,6 @@ // limitations under the License. // -import GemCommonsKit @testable import HealthCardAccess import Nimble import XCTest diff --git a/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift b/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift index bd09350..cc25269 100644 --- a/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift +++ b/Tests/HealthCardAccessTests/CardObjects/GemCvCertificateTest.swift @@ -15,7 +15,6 @@ // import ASN1Kit -import GemCommonsKit @testable import HealthCardAccess import Nimble import XCTest diff --git a/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift b/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift index 9c2bb4e..e32c9c4 100644 --- a/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift +++ b/Tests/HealthCardAccessTests/Commands/HCCExtPerformSecurityOperationTest.swift @@ -17,7 +17,6 @@ import ASN1Kit import CardReaderProviderApi import Foundation -import GemCommonsKit @testable import HealthCardAccess import Nimble import Security diff --git a/Tests/HealthCardAccessTests/Models/CardGenerationTest.swift b/Tests/HealthCardAccessTests/Models/CardGenerationTest.swift index c93140a..942dfa7 100644 --- a/Tests/HealthCardAccessTests/Models/CardGenerationTest.swift +++ b/Tests/HealthCardAccessTests/Models/CardGenerationTest.swift @@ -41,7 +41,7 @@ class CardGenerationTest: XCTestCase { expect(CardGeneration.parseCardGeneration(data: Data([0x4, 0x03, 0x63]))) == .g2 expect(CardGeneration.parseCardGeneration(data: Data([0x4, 0x04, 0x00]))) == .g2_1 expect(CardGeneration.parseCardGeneration(data: Data([0x5, 0x00, 0x00]))) == .g2_1 - expect(CardGeneration.parseCardGeneration(data: Data.empty)).to(beNil()) + expect(CardGeneration.parseCardGeneration(data: Data())).to(beNil()) } static let allTests = [ diff --git a/Tests/HealthCardAccessTests/ResourceLoader.swift b/Tests/HealthCardAccessTests/ResourceLoader.swift new file mode 100644 index 0000000..30e0cec --- /dev/null +++ b/Tests/HealthCardAccessTests/ResourceLoader.swift @@ -0,0 +1,108 @@ +// 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/HealthCardControlTests/Crypto/AESTests.swift b/Tests/HealthCardControlTests/Crypto/AESTests.swift index 34ba2c8..8f187a1 100644 --- a/Tests/HealthCardControlTests/Crypto/AESTests.swift +++ b/Tests/HealthCardControlTests/Crypto/AESTests.swift @@ -15,7 +15,6 @@ // import CommonCrypto -import GemCommonsKit @testable import HealthCardControl import Nimble import XCTest diff --git a/Tests/HealthCardControlTests/ResourceLoader.swift b/Tests/HealthCardControlTests/ResourceLoader.swift new file mode 100644 index 0000000..30e0cec --- /dev/null +++ b/Tests/HealthCardControlTests/ResourceLoader.swift @@ -0,0 +1,108 @@ +// 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/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift b/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift index ec62ba3..5a9b8b8 100644 --- a/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift +++ b/Tests/HealthCardControlTests/SecureMessaging/HealthCardTypeExtESIGNTest.swift @@ -16,7 +16,6 @@ import CardReaderProviderApi import Combine -import GemCommonsKit import HealthCardAccess @testable import HealthCardControl import Nimble diff --git a/Tests/Util/AnyPublisher+Test.swift b/Tests/Util/AnyPublisher+Test.swift index 70c1afd..815f2ab 100644 --- a/Tests/Util/AnyPublisher+Test.swift +++ b/Tests/Util/AnyPublisher+Test.swift @@ -16,7 +16,6 @@ import Combine import Foundation -import GemCommonsKit extension AnyPublisher { /// Convenience function for testing a Publisher's emitted values diff --git a/project.yml b/project.yml index 1bea5fa..18ae3c2 100644 --- a/project.yml +++ b/project.yml @@ -55,9 +55,6 @@ packages: ASN1Kit: url: https://github.com/gematik/ASN1Kit majorVersion: 1.2.0 - GemCommonsKit: - url: https://github.com/gematik/ref-GemCommonsKit.git - majorVersion: 1.3.0 OpenSSL-Swift: url: https://github.com/gematik/OpenSSL-Swift majorVersion: 4.2.0 @@ -110,8 +107,6 @@ targets: - target: Helper_iOS - package: ASN1Kit - package: OpenSSL-Swift - - package: GemCommonsKit - product: GemCommonsKit - target: HealthCardAccess_iOS - target: HealthCardControl_iOS - sdk: CoreNFC.framework @@ -137,8 +132,6 @@ targets: info: path: Resources/CardReaderProviderApi_Info.plist dependencies: - - package: GemCommonsKit - product: GemCommonsKit - target: Helper_${platform} scheme: testTargets: @@ -176,8 +169,6 @@ targets: - Tests/CardReaderProviderApiTests dependencies: - target: CardReaderProviderApi_${platform} - - package: GemCommonsKit - product: GemCommonsKit - framework: Carthage/Build/Nimble.xcframework CardReaderAccessTests: type: bundle.unit-test @@ -216,8 +207,6 @@ targets: dependencies: - target: HealthCardAccess_${platform} - package: ASN1Kit - - package: GemCommonsKit - product: GemCommonsKit - framework: Carthage/Build/Nimble.xcframework - target: Util_${platform} HealthCardControl: @@ -247,8 +236,6 @@ targets: dependencies: - target: HealthCardControl_${platform} - target: Util_${platform} - - package: GemCommonsKit - product: GemCommonsKit - framework: Carthage/Build/Nimble.xcframework - sdk: Combine.framework NFCCardReaderProvider: @@ -262,8 +249,6 @@ targets: - target: HealthCardAccess_iOS - target: HealthCardControl_iOS - target: Helper_iOS - - package: GemCommonsKit - product: GemCommonsKit - sdk: CoreNFC.framework scheme: testTargets: @@ -287,8 +272,6 @@ targets: sources: - Tests/Util dependencies: - - package: GemCommonsKit - product: GemCommonsKit - sdk: Combine.framework buildImplicitDependencies: true