From ec26ed04e474ad805685e0eb6ab07a1842adb2ca Mon Sep 17 00:00:00 2001 From: enebin Date: Fri, 30 Jun 2023 13:46:46 +0900 Subject: [PATCH] Update tests --- Demo/Aespa-iOS/VideoContentViewModel.swift | 18 +++--- README.md | 23 ++++++- Sources/Aespa/AespaSession.swift | 62 +++++++++++++----- .../Core/Context/AespaVideoContext.swift | 20 ++++-- Sources/Aespa/Core/Context/Context.swift | 64 +++++++++++++++---- .../AVCaptureDevice+AespaRepresentable.swift | 7 +- .../Tuner/Device/ChangeMonitoringTuner.swift | 2 +- Sources/Aespa/Util/Log/Logger.swift | 9 ++- Sources/Aespa/View/InteractivePreview.swift | 26 +++++--- Tests/Tests/Tuner/DeviceTunerTests.swift | 15 +++-- Tests/Tests/Tuner/SessionTunerTests.swift | 58 +---------------- 11 files changed, 183 insertions(+), 121 deletions(-) diff --git a/Demo/Aespa-iOS/VideoContentViewModel.swift b/Demo/Aespa-iOS/VideoContentViewModel.swift index 103d357..7862117 100644 --- a/Demo/Aespa-iOS/VideoContentViewModel.swift +++ b/Demo/Aespa-iOS/VideoContentViewModel.swift @@ -14,9 +14,12 @@ import Aespa class VideoContentViewModel: ObservableObject { let aespaSession: AespaSession - var preview: InteractivePreview { - let option = InteractivePreviewOption(enableShowingCrosshair: false) - return aespaSession.interactivePreview(option: option) + var preview: some View { + return aespaSession.interactivePreview() + + // Or you can give some options +// let option = InteractivePreviewOption(enableShowingCrosshair: false) +// return aespaSession.interactivePreview(option: option) } private var subscription = Set() @@ -93,13 +96,8 @@ class VideoContentViewModel: ObservableObject { func fetchPhotoFiles() { // File fetching task can cause low reponsiveness when called from main thread - DispatchQueue.global().async { - let fetchedFiles = self.aespaSession.fetchPhotoFiles() - - DispatchQueue.main.async { - self.photoFiles = fetchedFiles - } - } + let fetchedFiles = self.aespaSession.fetchPhotoFiles() + self.photoFiles = fetchedFiles } } diff --git a/README.md b/README.md index 19365e6..3dd5fe3 100644 --- a/README.md +++ b/README.md @@ -133,8 +133,8 @@ One of our main feature, `InteractivePreview` provides a comprehensive and intui | Features | Description | |------------------------|------------------------------------------------------------------------------------------------------------------| -| Tap-to-focus | Adjusts the focus of the camera based on the tapped area on the screen. | -| Double tap camera change | Switches between the front and back camera upon double tapping. | +| Tap to focus | Adjusts the focus of the camera based on the tapped area on the screen. | +| Double tap to change camera | Switches between the front and back camera upon double tapping. | | Pinch zoom | Allows zooming in or out on the preview by using a pinch gesture. | @@ -235,9 +235,26 @@ aespaSession.stopRecording() // Capture photo aespaSession.capturePhoto() ``` +### Get result +``` Swift +aespaSession.stopRecording { result in + switch result { + case .success(let file): + // + case .failure(let error): + print(error) + } +} + +// or +aespaSession.fetchVideoFiles(limit: 1) + +// or you can use publisher +aespaSession.videoFilePublisher.sink { result in ... } +``` ## SwiftUI Integration -Aespa also provides a super-easy way to integrate video capture functionality into SwiftUI applications. AespaSession includes a helper method to create a SwiftUI `UIViewRepresentable` that provides a preview of the video capture. +Aespa also provides a super-easy way to integrate video capture functionality into SwiftUI applications. `AespaSession` includes a helper method to create a SwiftUI `UIViewRepresentable` that provides a preview of the video capture. ### Example usage diff --git a/Sources/Aespa/AespaSession.swift b/Sources/Aespa/AespaSession.swift index 139b5c0..e568c42 100644 --- a/Sources/Aespa/AespaSession.swift +++ b/Sources/Aespa/AespaSession.swift @@ -103,6 +103,7 @@ open class AespaSession { coreSession } + /// This property indicates whether the current session is active or not. public var isRunning: Bool { coreSession.isRunning } @@ -137,6 +138,10 @@ open class AespaSession { return device.position } + /// This property indicates whether the camera device is set to monitor changes in the subject area. + /// + /// Enabling subject area change monitoring allows the device to adjust focus and exposure settings automatically + /// when the subject within the specified area changes. public var isSubjectAreaChangeMonitoringEnabled: Bool? { guard let device = coreSession.videoDeviceInput?.device else { return nil } return device.isSubjectAreaChangeMonitoringEnabled @@ -155,7 +160,12 @@ open class AespaSession { } // MARK: - Utilities - + /// Returns a publisher that emits a `Notification` when the subject area of the capture device changes. + /// + /// This is useful when you want to react to changes in the capture device's subject area, + /// such as when the user changes the zoom factor, or when the device changes its autofocus area. + /// + /// - Returns: An `AnyPublisher` instance that emits `Notification` values. public func getSubjectAreaDidChangePublisher() -> AnyPublisher { return NotificationCenter.default .publisher(for: NSNotification.Name.AVCaptureDeviceSubjectAreaDidChange) @@ -199,34 +209,46 @@ extension AespaSession: CommonContext { } @discardableResult - public func quality(to preset: AVCaptureSession.Preset, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func quality( + to preset: AVCaptureSession.Preset, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaSession { let tuner = QualityTuner(videoQuality: preset) coreSession.run(tuner, onComplete) return self } - + @discardableResult - public func position(to position: AVCaptureDevice.Position, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func position( + to position: AVCaptureDevice.Position, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaSession { let tuner = CameraPositionTuner(position: position, devicePreference: option.session.cameraDevicePreference) coreSession.run(tuner, onComplete) return self } - + @discardableResult - public func orientation(to orientation: AVCaptureVideoOrientation, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func orientation( + to orientation: AVCaptureVideoOrientation, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaSession { let tuner = VideoOrientationTuner(orientation: orientation) coreSession.run(tuner, onComplete) return self } - + @discardableResult - public func focus(mode: AVCaptureDevice.FocusMode, point: CGPoint? = nil, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func focus( + mode: AVCaptureDevice.FocusMode, point: CGPoint? = nil, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaSession { let tuner = FocusTuner(mode: mode, point: point) coreSession.run(tuner, onComplete) return self } - + @discardableResult public func zoom(factor: CGFloat, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { let tuner = ZoomTuner(zoomFactor: factor) @@ -235,14 +257,17 @@ extension AespaSession: CommonContext { } @discardableResult - public func changeMonitoring(enabled: Bool, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func changeMonitoring(enabled: Bool, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { let tuner = ChangeMonitoringTuner(isSubjectAreaChangeMonitoringEnabled: enabled) coreSession.run(tuner, onComplete) return self } @discardableResult - public func custom(_ tuner: T, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaSession { + public func custom( + _ tuner: T, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaSession { coreSession.run(tuner, onComplete) return self } @@ -286,15 +311,22 @@ extension AespaSession: VideoContext { } @discardableResult - public func stabilization(mode: AVCaptureVideoStabilizationMode, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaVideoSessionContext { + public func stabilization( + mode: AVCaptureVideoStabilizationMode, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaVideoSessionContext { videoContext.stabilization(mode: mode, onComplete) } - + @discardableResult - public func torch(mode: AVCaptureDevice.TorchMode, level: Float, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaVideoSessionContext { + public func torch( + mode: AVCaptureDevice.TorchMode, + level: Float, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaVideoSessionContext { videoContext.torch(mode: mode, level: level, onComplete) } - + public func fetchVideoFiles(limit: Int = 0) -> [VideoFile] { videoContext.fetchVideoFiles(limit: limit) } diff --git a/Sources/Aespa/Core/Context/AespaVideoContext.swift b/Sources/Aespa/Core/Context/AespaVideoContext.swift index ab0a78c..a705314 100644 --- a/Sources/Aespa/Core/Context/AespaVideoContext.swift +++ b/Sources/Aespa/Core/Context/AespaVideoContext.swift @@ -131,7 +131,10 @@ extension AespaVideoContext: VideoContext { } @discardableResult - public func stabilization(mode: AVCaptureVideoStabilizationMode, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaVideoContext { + public func stabilization( + mode: AVCaptureVideoStabilizationMode, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaVideoContext { let tuner = VideoStabilizationTuner(stabilzationMode: mode) coreSession.run(tuner, onComplete) @@ -139,19 +142,26 @@ extension AespaVideoContext: VideoContext { } @discardableResult - public func torch(mode: AVCaptureDevice.TorchMode, level: Float, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaVideoContext { + public func torch( + mode: AVCaptureDevice.TorchMode, + level: Float, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaVideoContext { let tuner = TorchTuner(level: level, torchMode: mode) coreSession.run(tuner, onComplete) return self } - - public func customize(_ tuner: T, _ onComplete: @escaping CompletionHandler = { _ in }) -> AespaVideoContext { + + public func customize( + _ tuner: T, + _ onComplete: @escaping CompletionHandler = { _ in } + ) -> AespaVideoContext { coreSession.run(tuner, onComplete) return self } - + public func fetchVideoFiles(limit: Int = 0) -> [VideoFile] { return fileManager.fetchVideo( albumName: option.asset.albumName, diff --git a/Sources/Aespa/Core/Context/Context.swift b/Sources/Aespa/Core/Context/Context.swift index 519b411..ea76544 100644 --- a/Sources/Aespa/Core/Context/Context.swift +++ b/Sources/Aespa/Core/Context/Context.swift @@ -10,8 +10,11 @@ import Combine import Foundation import AVFoundation -/// +/// A type representing a closure that handles a completion event with potential errors. public typealias CompletionHandler = (Result) -> Void + +/// A type representing a closure that handles a result of an operation +/// that produces a value of type `T`, with potential errors. public typealias ResultHandler = (Result) -> Void /// A protocol that defines the common behaviors and properties that all context types must implement. @@ -19,8 +22,9 @@ public typealias ResultHandler = (Result) -> Void /// It includes methods to control the quality, position, orientation, and auto-focusing behavior /// of the session. It also includes the ability to adjust the zoom level of the session. public protocol CommonContext { + /// associatedtype CommonContextType: CommonContext & VideoContext & PhotoContext - + /// var underlyingCommonContext: CommonContextType { get } /// Sets the quality preset for the video recording session. @@ -30,7 +34,10 @@ public protocol CommonContext { /// - onComplete: A closure to be executed if the session fails to run the tuner. /// /// - Returns: `AespaVideoContext`, for chaining calls. - @discardableResult func quality(to preset: AVCaptureSession.Preset, _ onComplete: @escaping CompletionHandler) -> CommonContextType + @discardableResult func quality( + to preset: AVCaptureSession.Preset, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType /// Sets the camera position for the video recording session. /// @@ -41,7 +48,10 @@ public protocol CommonContext { /// - onComplete: A closure to be executed if the session fails to run the tuner. /// /// - Returns: `AespaVideoContext`, for chaining calls. - @discardableResult func position(to position: AVCaptureDevice.Position, _ onComplete: @escaping CompletionHandler) -> CommonContextType + @discardableResult func position( + to position: AVCaptureDevice.Position, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType /// Sets the orientation for the session. /// @@ -51,8 +61,12 @@ public protocol CommonContext { /// /// - Returns: `AespaVideoContext`, for chaining calls. /// - /// - Note: It sets the orientation of the video you are recording, not the orientation of the `AVCaptureVideoPreviewLayer`. - @discardableResult func orientation(to orientation: AVCaptureVideoOrientation, _ onComplete: @escaping CompletionHandler) -> CommonContextType + /// - Note: It sets the orientation of the video you are recording, + /// not the orientation of the `AVCaptureVideoPreviewLayer`. + @discardableResult func orientation( + to orientation: AVCaptureVideoOrientation, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType /// Sets the autofocusing mode for the video recording session. /// @@ -62,7 +76,11 @@ public protocol CommonContext { /// - onComplete: A closure to be executed if the session fails to run the tuner. /// /// - Returns: `AespaVideoContext`, for chaining calls. - @discardableResult func focus(mode: AVCaptureDevice.FocusMode, point: CGPoint?, _ onComplete: @escaping CompletionHandler) -> CommonContextType + @discardableResult func focus( + mode: AVCaptureDevice.FocusMode, + point: CGPoint?, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType /// Sets the zoom factor for the video recording session. /// @@ -80,7 +98,10 @@ public protocol CommonContext { /// - onComplete: A closure to be executed if the session fails to run the tuner. /// /// - Returns: `AespaVideoContext`, for chaining calls. - @discardableResult func changeMonitoring(enabled: Bool, _ onComplete: @escaping CompletionHandler) -> CommonContextType + @discardableResult func changeMonitoring( + enabled: Bool, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType /// This function provides a way to use a custom tuner to modify the current session. /// The tuner must conform to `AespaSessionTuning`. @@ -90,7 +111,10 @@ public protocol CommonContext { /// - onComplete: A closure to be executed if the session fails to run the tuner. /// /// - Returns: `AespaVideoContext`, for chaining calls. - @discardableResult func custom(_ tuner: T, _ onComplete: @escaping CompletionHandler) -> CommonContextType + @discardableResult func custom( + _ tuner: T, + _ onComplete: @escaping CompletionHandler + ) -> CommonContextType } /// A protocol that defines the behaviors and properties specific to the video context. @@ -99,7 +123,9 @@ public protocol CommonContext { /// the session is currently recording or muted, and controlling video recording, /// stabilization, torch mode, and fetching recorded video files. public protocol VideoContext { + /// associatedtype VideoContextType: VideoContext + /// var underlyingVideoContext: VideoContextType { get } /// A Boolean value that indicates whether the session is currently recording video. @@ -126,7 +152,14 @@ public protocol VideoContext { /// it sets the orientation according to the current device orientation. func startRecording(_ onComplete: @escaping CompletionHandler) - func stopRecording(_ completionHandler: @escaping (Result) -> Void) + /// Stops the current recording session and saves the video file. + /// + /// Once the recording session is successfully stopped and the video file is saved, + /// this function invokes a completion handler with the resulting `VideoFile` instance or an error. + /// + /// - Parameter onComplete: A closure to be called after the recording has stopped + /// and the video file is saved or failed. + func stopRecording(_ onComplete: @escaping (Result) -> Void) /// Mutes the audio input for the video recording session. /// @@ -152,7 +185,10 @@ public protocol VideoContext { /// /// - Returns: The modified `VideoContextType` for chaining calls. @discardableResult - func stabilization(mode: AVCaptureVideoStabilizationMode, _ onComplete: @escaping CompletionHandler) -> VideoContextType + func stabilization( + mode: AVCaptureVideoStabilizationMode, + _ onComplete: @escaping CompletionHandler + ) -> VideoContextType /// Sets the torch mode and level for the video recording session. /// @@ -165,7 +201,11 @@ public protocol VideoContext { /// - Note: This function might throw an error if the torch mode is not supported, /// or the specified level is not within the acceptable range. @discardableResult - func torch(mode: AVCaptureDevice.TorchMode, level: Float, _ onComplete: @escaping CompletionHandler) -> VideoContextType + func torch( + mode: AVCaptureDevice.TorchMode, + level: Float, + _ onComplete: @escaping CompletionHandler + ) -> VideoContextType /// Fetches a list of recorded video files. /// The number of files fetched is controlled by the limit parameter. diff --git a/Sources/Aespa/Core/Representable/AVCaptureDevice+AespaRepresentable.swift b/Sources/Aespa/Core/Representable/AVCaptureDevice+AespaRepresentable.swift index 39f400d..cb7cccf 100644 --- a/Sources/Aespa/Core/Representable/AVCaptureDevice+AespaRepresentable.swift +++ b/Sources/Aespa/Core/Representable/AVCaptureDevice+AespaRepresentable.swift @@ -8,7 +8,7 @@ import Foundation import AVFoundation -protocol AespaCaptureDeviceRepresentable: NSObject { +protocol AespaCaptureDeviceRepresentable { var hasTorch: Bool { get } var focusMode: AVCaptureDevice.FocusMode { get set } var isSubjectAreaChangeMonitoringEnabled: Bool { get set } @@ -22,6 +22,7 @@ protocol AespaCaptureDeviceRepresentable: NSObject { func zoomFactor(_ factor: CGFloat) func setFocusMode(_ focusMode: AVCaptureDevice.FocusMode, point: CGPoint?) throws func torchMode(_ torchMode: AVCaptureDevice.TorchMode) + func enableMonitoring(_ enabled: Bool) func setTorchModeOn(level torchLevel: Float) throws } @@ -38,6 +39,10 @@ extension AVCaptureDevice: AespaCaptureDeviceRepresentable { self.torchMode = .off } } + + func enableMonitoring(_ enabled: Bool) { + self.isSubjectAreaChangeMonitoringEnabled = enabled + } func setFocusMode(_ focusMode: AVCaptureDevice.FocusMode, point: CGPoint?) throws { if isAdjustingFocus { diff --git a/Sources/Aespa/Tuner/Device/ChangeMonitoringTuner.swift b/Sources/Aespa/Tuner/Device/ChangeMonitoringTuner.swift index 74c8e28..6ecee84 100644 --- a/Sources/Aespa/Tuner/Device/ChangeMonitoringTuner.swift +++ b/Sources/Aespa/Tuner/Device/ChangeMonitoringTuner.swift @@ -18,6 +18,6 @@ struct ChangeMonitoringTuner: AespaDeviceTuning { } func tune(_ device: T) throws { - device.isSubjectAreaChangeMonitoringEnabled = enabled + device.enableMonitoring(enabled) } } diff --git a/Sources/Aespa/Util/Log/Logger.swift b/Sources/Aespa/Util/Log/Logger.swift index f925865..2251eff 100644 --- a/Sources/Aespa/Util/Log/Logger.swift +++ b/Sources/Aespa/Util/Log/Logger.swift @@ -23,8 +23,13 @@ class Logger { ) { if enableLogging { let timestamp = Date().description - - print("[⚠️ Aespa Error] \(timestamp) | Method: \(method) | Error: \(error) | Description: \(error.localizedDescription) | Message: \(message)") + print( + "[⚠️ Aespa Error] \(timestamp) |" + + " Method: \(method) |" + + " Error: \(error) |" + + " Description: \(error.localizedDescription) |" + + " Message: \(message)" + ) } } } diff --git a/Sources/Aespa/View/InteractivePreview.swift b/Sources/Aespa/View/InteractivePreview.swift index 62328d3..d1c8401 100644 --- a/Sources/Aespa/View/InteractivePreview.swift +++ b/Sources/Aespa/View/InteractivePreview.swift @@ -9,17 +9,27 @@ import Combine import SwiftUI import AVFoundation +/// Struct that contains the options for customizing an `InteractivePreview`. +/// +/// The options include enabling or disabling certain interactive features such as changing position, +/// zooming, focusing, adjusting focus mode when moved, and showing a crosshair. public struct InteractivePreviewOption { - // Position + /// Flag that controls whether the camera position can be changed. Default is `true`. public var enableChangePosition = true - // Zoom + + /// Flag that controls whether zoom functionality is enabled. Default is `true`. public var enableZoom = true - // Foocus + + /// Flag that controls whether focus can be manually adjusted. Default is `true`. public var enableFocus = true + + /// Flag that controls whether the focus mode is changed when the camera is moved. Default is `true`. public var enableChangeFocusModeWhenMoved = true - // Crosshair - public var enableShowingCrosshair = true + /// Flag that controls whether a crosshair is displayed on the preview. Default is `true`. + public var enableShowingCrosshair = true + + /// Initialize the option public init( enableChangePosition: Bool = true, enableZoom: Bool = true, @@ -109,7 +119,7 @@ public struct InteractivePreview: View { private extension InteractivePreview { var changePositionGesture: some Gesture { guard session.isRunning, option.enableChangePosition else { - return TapGesture(count: 2).onEnded{} + return TapGesture(count: 2).onEnded {} } return TapGesture(count: 2).onEnded { @@ -120,7 +130,7 @@ private extension InteractivePreview { func tapToFocusGesture(_ geometry: GeometryProxy) -> some Gesture { guard session.isRunning, option.enableFocus else { - return DragGesture(minimumDistance: 0).onEnded{ _ in } + return DragGesture(minimumDistance: 0).onEnded { _ in } } return DragGesture(minimumDistance: 0) @@ -139,7 +149,7 @@ private extension InteractivePreview { ) print(point) - session.focus(mode: .autoFocus, point: point) { result in + session.focus(mode: .autoFocus, point: point) { _ in print("Done") } focusingLocation = value.location diff --git a/Tests/Tests/Tuner/DeviceTunerTests.swift b/Tests/Tests/Tuner/DeviceTunerTests.swift index 4b717df..4fd5a8f 100644 --- a/Tests/Tests/Tuner/DeviceTunerTests.swift +++ b/Tests/Tests/Tuner/DeviceTunerTests.swift @@ -22,22 +22,23 @@ final class DeviceTunerTests: XCTestCase { override func tearDownWithError() throws { device = nil } - - func testAutoFocusTuner() throws { + + func testFocusTuner() throws { let mode = AVCaptureDevice.FocusMode.locked let point = CGPoint() - let tuner = AutoFocusTuner(mode: mode, point: point) + let tuner = FocusTuner(mode: mode, point: point) stub(device) { proxy in when(proxy.isFocusModeSupported(equal(to: mode))).thenReturn(true) - when(proxy.focusMode(equal(to: mode), point: equal(to: point))).then { mode in + when(proxy.setFocusMode(equal(to: mode), + point: equal(to: point))).then { mode in when(proxy.focusMode.get).thenReturn(.locked) } } try tuner.tune(device) verify(device) - .focusMode(equal(to: mode), point: equal(to: point)) + .setFocusMode(equal(to: mode), point: equal(to: point)) .with(returnType: Void.self) XCTAssertEqual(device.focusMode, mode) @@ -69,7 +70,7 @@ final class DeviceTunerTests: XCTestCase { stub(device) { proxy in when(proxy.hasTorch.get).thenReturn(true) when(proxy.torchMode(equal(to: mode))).thenDoNothing() - when(proxy.torchModeOn(level: level)).thenDoNothing() + when(proxy.setTorchModeOn(level: level)).thenDoNothing() } try tuner.tune(device) @@ -78,7 +79,7 @@ final class DeviceTunerTests: XCTestCase { .with(returnType: Void.self) verify(device) - .torchModeOn(level: level) + .setTorchModeOn(level: level) .with(returnType: Void.self) } } diff --git a/Tests/Tests/Tuner/SessionTunerTests.swift b/Tests/Tests/Tuner/SessionTunerTests.swift index c1eaac2..1b07311 100644 --- a/Tests/Tests/Tuner/SessionTunerTests.swift +++ b/Tests/Tests/Tuner/SessionTunerTests.swift @@ -16,7 +16,7 @@ final class SessionTunerTests: XCTestCase { var mockSessionProtocol: MockAespaCoreSessionRepresentable! - override func upWithError() throws { + override func setUpWithError() throws { mockSessionProtocol = MockAespaCoreSessionRepresentable() } @@ -68,62 +68,6 @@ final class SessionTunerTests: XCTestCase { verify(mockSessionProtocol).removeAudioInput() } - func testSessionLaunchTuner_whenNotRunning() throws { - stub(mockSessionProtocol) { proxy in - when(proxy.isRunning.get).thenReturn(false) - - when(proxy.addMovieInput()).thenDoNothing() - when(proxy.addMovieFileOutput()).thenDoNothing() - when(proxy.addCapturePhotoOutput()).thenDoNothing() - - when(proxy.startRunning()).thenDoNothing() - } - - let tuner = SessionLaunchTuner() - try tuner.tune(mockSessionProtocol) - - verify(mockSessionProtocol) - .addMovieInput() - .with(returnType: Void.self) - - verify(mockSessionProtocol) - .addMovieFileOutput() - .with(returnType: Void.self) - - verify(mockSessionProtocol) - .addCapturePhotoOutput() - .with(returnType: Void.self) - - verify(mockSessionProtocol) - .startRunning() - .with(returnType: Void.self) - } - - func testSessionLaunchTuner_whenRunning() throws { - stub(mockSessionProtocol) { proxy in - when(proxy.isRunning.get).thenReturn(true) - } - - let tuner = SessionLaunchTuner() - try tuner.tune(mockSessionProtocol) - - verify(mockSessionProtocol, never()) - .addMovieInput() - .with(returnType: Void.self) - - verify(mockSessionProtocol, never()) - .addMovieFileOutput() - .with(returnType: Void.self) - - verify(mockSessionProtocol, never()) - .addCapturePhotoOutput() - .with(returnType: Void.self) - - verify(mockSessionProtocol, never()) - .startRunning() - .with(returnType: Void.self) - } - func testSessionTerminationTuner_whenRunning() throws { stub(mockSessionProtocol) { proxy in when(proxy.isRunning.get).thenReturn(true)