392 lines
15 KiB
Swift
392 lines
15 KiB
Swift
//
|
||
// Tests+CameraManager.swift of MijickCamera
|
||
//
|
||
// Created by Tomasz Kurylik. Sending ❤️ from Kraków!
|
||
// - Mail: tomasz.kurylik@mijick.com
|
||
// - GitHub: https://github.com/FulcrumOne
|
||
// - Medium: https://medium.com/@mijick
|
||
//
|
||
// Copyright ©2024 Mijick. All rights reserved.
|
||
|
||
|
||
import Testing
|
||
import SwiftUI
|
||
@testable import MijickCamera
|
||
|
||
@MainActor @Suite("Camera Manager Tests") struct CameraManagerTests {
|
||
var cameraManager: CameraManager = .init(
|
||
captureSession: MockCaptureSession(),
|
||
captureDeviceInputType: MockDeviceInput.self
|
||
)
|
||
}
|
||
|
||
// MARK: Setup
|
||
extension CameraManagerTests {
|
||
@Test("Setup: Default Attributes") func setupWithDefaultAttributes() async throws {
|
||
try await setupCamera()
|
||
|
||
#expect(cameraManager.captureSession.isRunning == true)
|
||
#expect(cameraManager.captureSession.deviceInputs.count == 2)
|
||
#expect(cameraManager.photoOutput.parent != nil)
|
||
#expect(cameraManager.videoOutput.parent != nil)
|
||
#expect(cameraManager.captureSession.outputs.count == 3)
|
||
#expect(cameraManager.cameraView != nil)
|
||
#expect(cameraManager.cameraLayer.isHidden == true)
|
||
#expect(cameraManager.cameraMetalView.parent != nil)
|
||
#expect(cameraManager.cameraGridView.parent != nil)
|
||
#expect(cameraManager.motionManager.manager.accelerometerUpdateInterval > 0)
|
||
#expect(cameraManager.notificationCenterManager.parent != nil)
|
||
}
|
||
@Test("Setup: Custom Attributes") func setupWithCustomAttributes() async throws {
|
||
cameraManager.attributes.cameraPosition = .front
|
||
cameraManager.attributes.zoomFactor = 2137
|
||
cameraManager.attributes.lightMode = .on
|
||
cameraManager.attributes.resolution = .hd1280x720
|
||
cameraManager.attributes.frameRate = 666
|
||
cameraManager.attributes.cameraExposure.duration = .init(value: 1, timescale: 10)
|
||
cameraManager.attributes.cameraExposure.targetBias = 0.66
|
||
cameraManager.attributes.cameraExposure.iso = 2000
|
||
cameraManager.attributes.cameraExposure.mode = .custom
|
||
cameraManager.attributes.hdrMode = .off
|
||
cameraManager.attributes.isGridVisible = false
|
||
|
||
try await setupCamera()
|
||
|
||
#expect(currentDevice.uniqueID == cameraManager.frontCameraInput?.device.uniqueID)
|
||
#expect(currentDevice.videoZoomFactor == currentDevice.maxAvailableVideoZoomFactor)
|
||
#expect(currentDevice.lightMode == .on)
|
||
#expect(cameraManager.captureSession.sessionPreset == .hd1280x720)
|
||
#expect(currentDevice.activeVideoMinFrameDuration == .init(value: 1, timescale: Int32(currentDevice.maxFrameRate!)))
|
||
#expect(currentDevice.activeVideoMaxFrameDuration == .init(value: 1, timescale: Int32(currentDevice.maxFrameRate!)))
|
||
#expect(currentDevice.exposureDuration == .init(value: 1, timescale: 10))
|
||
#expect(currentDevice.exposureTargetBias == 0.66)
|
||
#expect(currentDevice.iso == currentDevice.maxISO)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(currentDevice.hdrMode == .off)
|
||
#expect(cameraManager.cameraGridView.alpha == 0)
|
||
|
||
#expect(cameraManager.attributes.zoomFactor == currentDevice.maxAvailableVideoZoomFactor)
|
||
#expect(cameraManager.attributes.frameRate == Int32(currentDevice.maxFrameRate!))
|
||
#expect(cameraManager.attributes.cameraExposure.iso == currentDevice.maxISO)
|
||
}
|
||
@Test("Setup: Audio Source Unavailable") func setupWithAudioSourceUnavailable() async throws {
|
||
cameraManager.attributes.isAudioSourceAvailable = false
|
||
try await setupCamera()
|
||
|
||
#expect(cameraManager.captureSession.deviceInputs.count == 1)
|
||
}
|
||
}
|
||
|
||
// MARK: Cancel
|
||
extension CameraManagerTests {
|
||
@Test("Cancel Camera Session") func cancelCameraSession() async throws {
|
||
try await setupCamera()
|
||
cameraManager.cancel()
|
||
|
||
#expect(cameraManager.captureSession.isRunning == false)
|
||
#expect(cameraManager.captureSession.deviceInputs.count == 0)
|
||
#expect(cameraManager.captureSession.outputs.count == 0)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Camera Output
|
||
extension CameraManagerTests {
|
||
@Test("Set Camera Output") func setCameraOutput() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setOutputType(.photo)
|
||
#expect(cameraManager.attributes.outputType == .photo)
|
||
|
||
cameraManager.setOutputType(.video)
|
||
#expect(cameraManager.attributes.outputType == .video)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Camera Position
|
||
extension CameraManagerTests {
|
||
@Test("Set Camera Position") func setCameraPosition() async throws {
|
||
try await setupCamera()
|
||
|
||
try await cameraManager.setCameraPosition(.front)
|
||
#expect(cameraManager.captureSession.deviceInputs.count == 2)
|
||
#expect(currentDevice.uniqueID == cameraManager.frontCameraInput?.device.uniqueID)
|
||
#expect(cameraManager.attributes.cameraPosition == .front)
|
||
|
||
await Task.sleep(seconds: 0.5)
|
||
|
||
try await cameraManager.setCameraPosition(.back)
|
||
#expect(cameraManager.captureSession.deviceInputs.count == 2)
|
||
#expect(currentDevice.uniqueID == cameraManager.backCameraInput?.device.uniqueID)
|
||
#expect(cameraManager.attributes.cameraPosition == .back)
|
||
|
||
await Task.sleep(seconds: 0.5)
|
||
|
||
try cameraManager.setCameraZoomFactor(3.2)
|
||
try await cameraManager.setCameraPosition(.front)
|
||
#expect(currentDevice.videoZoomFactor == 1)
|
||
#expect(cameraManager.attributes.zoomFactor == 1)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Camera Zoom
|
||
extension CameraManagerTests {
|
||
@Test("Set Camera Zoom") func setCameraZoom() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setCameraZoomFactor(2.137)
|
||
#expect(currentDevice.videoZoomFactor == 2.137)
|
||
#expect(cameraManager.attributes.zoomFactor == 2.137)
|
||
|
||
try cameraManager.setCameraZoomFactor(0.2137)
|
||
#expect(currentDevice.videoZoomFactor == currentDevice.minAvailableVideoZoomFactor)
|
||
#expect(cameraManager.attributes.zoomFactor == currentDevice.minAvailableVideoZoomFactor)
|
||
|
||
try cameraManager.setCameraZoomFactor(213.7)
|
||
#expect(currentDevice.videoZoomFactor == currentDevice.maxAvailableVideoZoomFactor)
|
||
#expect(cameraManager.attributes.zoomFactor == currentDevice.maxAvailableVideoZoomFactor)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Camera Focus
|
||
extension CameraManagerTests {
|
||
@Test("Set Camera Focus") func setCameraFocus() async throws {
|
||
try await setupCamera()
|
||
|
||
let point = CGPoint(x: 213.7, y: 21.37)
|
||
let expectedPoint = CGPoint(x: point.y / cameraManager.cameraView.frame.height, y: 1 - point.x / cameraManager.cameraView.frame.width)
|
||
|
||
try cameraManager.setCameraFocus(at: point)
|
||
#expect(currentDevice.focusPointOfInterest == expectedPoint)
|
||
#expect(currentDevice.exposurePointOfInterest == expectedPoint)
|
||
#expect(currentDevice.focusMode == .autoFocus)
|
||
#expect(currentDevice.exposureMode == .autoExpose)
|
||
#expect(cameraManager.cameraView.subviews.filter { $0.tag == .focusIndicatorTag }.count == 1)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Flash Mode
|
||
extension CameraManagerTests {
|
||
@Test("Set Flash Mode") func setFlashMode() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setFlashMode(.on)
|
||
#expect(cameraManager.attributes.flashMode == .on)
|
||
|
||
cameraManager.setFlashMode(.auto)
|
||
#expect(cameraManager.attributes.flashMode == .auto)
|
||
|
||
cameraManager.setFlashMode(.off)
|
||
#expect(cameraManager.attributes.flashMode == .off)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Light Mode
|
||
extension CameraManagerTests {
|
||
@Test("Set Light Mode") func setLightMode() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setLightMode(.on)
|
||
#expect(currentDevice.lightMode == .on)
|
||
#expect(cameraManager.attributes.lightMode == .on)
|
||
|
||
try cameraManager.setLightMode(.off)
|
||
#expect(currentDevice.lightMode == .off)
|
||
#expect(cameraManager.attributes.lightMode == .off)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Mirror Output
|
||
extension CameraManagerTests {
|
||
@Test("Set Mirror Output") func setMirrorOutput() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setMirrorOutput(true)
|
||
#expect(cameraManager.attributes.mirrorOutput == true)
|
||
|
||
cameraManager.setMirrorOutput(false)
|
||
#expect(cameraManager.attributes.mirrorOutput == false)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Grid Visibility
|
||
extension CameraManagerTests {
|
||
@Test("Set Grid Visibility") func setGridVisibility() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setGridVisibility(true)
|
||
#expect(cameraManager.cameraGridView.alpha == 1)
|
||
#expect(cameraManager.attributes.isGridVisible == true)
|
||
|
||
cameraManager.setGridVisibility(false)
|
||
#expect(cameraManager.cameraGridView.alpha == 0)
|
||
#expect(cameraManager.attributes.isGridVisible == false)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Camera Filters
|
||
extension CameraManagerTests {
|
||
@Test("Set Camera Filters") func setCameraFilters() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setCameraFilters([.init(name: "CISepiaTone")!])
|
||
#expect(cameraManager.attributes.cameraFilters.count == 1)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Exposure Mode
|
||
extension CameraManagerTests {
|
||
@Test("Set Exposure Mode") func setExposureMode() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setExposureMode(.continuousAutoExposure)
|
||
#expect(currentDevice.exposureMode == .continuousAutoExposure)
|
||
#expect(cameraManager.attributes.cameraExposure.mode == .continuousAutoExposure)
|
||
|
||
try cameraManager.setExposureMode(.autoExpose)
|
||
#expect(currentDevice.exposureMode == .autoExpose)
|
||
#expect(cameraManager.attributes.cameraExposure.mode == .autoExpose)
|
||
|
||
try cameraManager.setExposureMode(.custom)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.mode == .custom)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Exposure Duration
|
||
extension CameraManagerTests {
|
||
@Test("Set Exposure Duration") func setExposureDuration() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setExposureDuration(.init(value: 1, timescale: 33))
|
||
#expect(currentDevice.exposureDuration == .init(value: 1, timescale: 33))
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.duration == .init(value: 1, timescale: 33))
|
||
|
||
try cameraManager.setExposureDuration(.init(value: 1, timescale: 100000))
|
||
#expect(currentDevice.exposureDuration == currentDevice.minExposureDuration)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.duration == currentDevice.minExposureDuration)
|
||
|
||
try cameraManager.setExposureDuration(.init(value: 1, timescale: 2))
|
||
#expect(currentDevice.exposureDuration == currentDevice.maxExposureDuration)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.duration == currentDevice.maxExposureDuration)
|
||
}
|
||
}
|
||
|
||
// MARK: Set ISO
|
||
extension CameraManagerTests {
|
||
@Test("Set ISO") func setISO() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setISO(1)
|
||
#expect(currentDevice.iso == 1)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.iso == 1)
|
||
|
||
try cameraManager.setISO(-2137)
|
||
#expect(currentDevice.iso == currentDevice.minISO)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.iso == currentDevice.minISO)
|
||
|
||
try cameraManager.setISO(2137)
|
||
#expect(currentDevice.iso == currentDevice.maxISO)
|
||
#expect(currentDevice.exposureMode == .custom)
|
||
#expect(cameraManager.attributes.cameraExposure.iso == currentDevice.maxISO)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Exposure Target Bias
|
||
extension CameraManagerTests {
|
||
@Test("Set Exposure Target Bias") func setExposureTargetBias() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setExposureTargetBias(1)
|
||
#expect(currentDevice.exposureTargetBias == 1)
|
||
#expect(cameraManager.attributes.cameraExposure.targetBias == 1)
|
||
|
||
try cameraManager.setExposureTargetBias(-2137)
|
||
#expect(currentDevice.exposureTargetBias == currentDevice.minExposureTargetBias)
|
||
#expect(cameraManager.attributes.cameraExposure.targetBias == currentDevice.minExposureTargetBias)
|
||
|
||
try cameraManager.setExposureTargetBias(2137)
|
||
#expect(currentDevice.exposureTargetBias == currentDevice.maxExposureTargetBias)
|
||
#expect(cameraManager.attributes.cameraExposure.targetBias == currentDevice.maxExposureTargetBias)
|
||
}
|
||
}
|
||
|
||
// MARK: Set HDR Mode
|
||
extension CameraManagerTests {
|
||
@Test("Set HDR Mode") func setHDRMode() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setHDRMode(.on)
|
||
#expect(currentDevice.hdrMode == .on)
|
||
#expect(cameraManager.attributes.hdrMode == .on)
|
||
|
||
try cameraManager.setHDRMode(.off)
|
||
#expect(currentDevice.hdrMode == .off)
|
||
#expect(cameraManager.attributes.hdrMode == .off)
|
||
|
||
try cameraManager.setHDRMode(.auto)
|
||
#expect(currentDevice.hdrMode == .auto)
|
||
#expect(cameraManager.attributes.hdrMode == .auto)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Resolution
|
||
extension CameraManagerTests {
|
||
@Test("Set Resolution") func setResolution() async throws {
|
||
try await setupCamera()
|
||
|
||
cameraManager.setResolution(.hd1280x720)
|
||
#expect(cameraManager.captureSession.sessionPreset == .hd1280x720)
|
||
#expect(cameraManager.attributes.resolution == .hd1280x720)
|
||
|
||
cameraManager.setResolution(.hd1920x1080)
|
||
#expect(cameraManager.captureSession.sessionPreset == .hd1920x1080)
|
||
#expect(cameraManager.attributes.resolution == .hd1920x1080)
|
||
|
||
cameraManager.setResolution(.cif352x288)
|
||
#expect(cameraManager.captureSession.sessionPreset == .cif352x288)
|
||
#expect(cameraManager.attributes.resolution == .cif352x288)
|
||
}
|
||
}
|
||
|
||
// MARK: Set Frame Rate
|
||
extension CameraManagerTests {
|
||
@Test("Set Frame Rate") func setFrameRate() async throws {
|
||
try await setupCamera()
|
||
|
||
try cameraManager.setFrameRate(45)
|
||
#expect(currentDevice.activeVideoMinFrameDuration == .init(value: 1, timescale: 45))
|
||
#expect(currentDevice.activeVideoMaxFrameDuration == .init(value: 1, timescale: 45))
|
||
#expect(cameraManager.attributes.frameRate == 45)
|
||
|
||
try cameraManager.setFrameRate(10)
|
||
#expect(currentDevice.activeVideoMinFrameDuration.timescale == Int32(currentDevice.minFrameRate!))
|
||
#expect(currentDevice.activeVideoMaxFrameDuration.timescale == Int32(currentDevice.minFrameRate!))
|
||
#expect(cameraManager.attributes.frameRate == Int32(currentDevice.minFrameRate!))
|
||
|
||
try cameraManager.setFrameRate(100)
|
||
#expect(currentDevice.activeVideoMinFrameDuration.timescale == Int32(currentDevice.maxFrameRate!))
|
||
#expect(currentDevice.activeVideoMaxFrameDuration.timescale == Int32(currentDevice.maxFrameRate!))
|
||
#expect(cameraManager.attributes.frameRate == Int32(currentDevice.maxFrameRate!))
|
||
}
|
||
}
|
||
|
||
|
||
// MARK: Helpers
|
||
private extension CameraManagerTests {
|
||
func setupCamera() async throws {
|
||
let cameraView = UIView(frame: .init(origin: .zero, size: .init(width: 1000, height: 1000)))
|
||
|
||
cameraManager.initialize(in: cameraView)
|
||
try await cameraManager.setup()
|
||
await Task.sleep(seconds: 10)
|
||
}
|
||
}
|
||
private extension CameraManagerTests {
|
||
var currentDevice: any CaptureDevice { cameraManager.getCameraInput()!.device }
|
||
}
|