248 lines
8.9 KiB
Swift
248 lines
8.9 KiB
Swift
// Copyright 2013 The Flutter Authors
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import AVFoundation
|
|
import XCTest
|
|
|
|
@testable import camera_avfoundation
|
|
|
|
/// Includes test cases related to photo capture operations for Camera class.
|
|
final class PhotoCaptureTests: XCTestCase {
|
|
private func createCam(with captureSessionQueue: DispatchQueue) -> DefaultCamera {
|
|
let configuration = CameraTestUtils.createTestCameraConfiguration()
|
|
configuration.captureSessionQueue = captureSessionQueue
|
|
return CameraTestUtils.createTestCamera(configuration)
|
|
}
|
|
|
|
func testCaptureToFile_mustReportErrorToResultIfSavePhotoDelegateCompletionsWithError() {
|
|
let errorExpectation = expectation(
|
|
description: "Must send error to result if save photo delegate completes with error.")
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let cam = createCam(with: captureSessionQueue)
|
|
let error = NSError(domain: "test", code: 0, userInfo: nil)
|
|
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate =
|
|
cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
// Completion runs on IO queue.
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(nil, error)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
// `Camera.captureToFile` runs on capture session queue.
|
|
captureSessionQueue.async {
|
|
cam.captureToFile { result in
|
|
switch result {
|
|
case .success(_):
|
|
XCTFail("Expected failure")
|
|
case .failure(_):
|
|
break
|
|
}
|
|
errorExpectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
|
|
func testCaptureToFile_mustReportPathToResultIfSavePhotoDelegateCompletionsWithPath() {
|
|
let pathExpectation = expectation(
|
|
description: "Must send file path to result if save photo delegate completes with file path.")
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let cam = createCam(with: captureSessionQueue)
|
|
let filePath = "test"
|
|
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate =
|
|
cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
// Completion runs on IO queue.
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(filePath, nil)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
// `Camera.captureToFile` runs on capture session queue.
|
|
captureSessionQueue.async {
|
|
cam.captureToFile { result in
|
|
switch result {
|
|
case .success(let result):
|
|
XCTAssertEqual(result, filePath)
|
|
case .failure(_):
|
|
XCTFail("Unexpected failure")
|
|
}
|
|
pathExpectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
|
|
func testCaptureToFile_mustReportFileExtensionWithHeifWhenHEVCIsAvailableAndFileFormatIsHEIF() {
|
|
let expectation = self.expectation(
|
|
description: "Test must set extension to heif if availablePhotoCodecTypes contains HEVC.")
|
|
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let cam = createCam(with: captureSessionQueue)
|
|
cam.setImageFileFormat(PlatformImageFileFormat.heif)
|
|
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.availablePhotoCodecTypes = [AVVideoCodecType.hevc]
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate =
|
|
cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
// Completion runs on IO queue.
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(delegate?.filePath, nil)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
// `Camera.captureToFile` runs on capture session queue.
|
|
captureSessionQueue.async {
|
|
cam.captureToFile { result in
|
|
if let filePath = self.assertSuccess(result) {
|
|
XCTAssertEqual((filePath as NSString).pathExtension, "heif")
|
|
}
|
|
expectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
|
|
func testCaptureToFile_mustReportFileExtensionWithJpgWhenHEVCNotAvailableAndFileFormatIsHEIF() {
|
|
let expectation = self.expectation(
|
|
description:
|
|
"Test must set extension to jpg if availablePhotoCodecTypes does not contain HEVC.")
|
|
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let cam = createCam(with: captureSessionQueue)
|
|
cam.setImageFileFormat(PlatformImageFileFormat.heif)
|
|
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate =
|
|
cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
// Completion runs on IO queue.
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(delegate?.filePath, nil)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
// `Camera.captureToFile` runs on capture session queue.
|
|
captureSessionQueue.async {
|
|
cam.captureToFile { result in
|
|
if let filePath = self.assertSuccess(result) {
|
|
XCTAssertEqual((filePath as NSString).pathExtension, "jpg")
|
|
}
|
|
expectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
|
|
func testCaptureToFile_handlesTorchMode() {
|
|
let pathExpectation = expectation(
|
|
description: "Must send file path to result if save photo delegate completes with file path.")
|
|
let setTorchExpectation = expectation(
|
|
description: "Should set torch mode to AVCaptureTorchModeOn.")
|
|
|
|
let captureDeviceMock = MockCaptureDevice()
|
|
captureDeviceMock.hasTorch = true
|
|
captureDeviceMock.isTorchAvailable = true
|
|
captureDeviceMock.getTorchModeStub = { .auto }
|
|
captureDeviceMock.setTorchModeStub = { mode in
|
|
if mode == .on {
|
|
setTorchExpectation.fulfill()
|
|
}
|
|
}
|
|
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let configuration = CameraTestUtils.createTestCameraConfiguration()
|
|
configuration.captureSessionQueue = captureSessionQueue
|
|
configuration.videoCaptureDeviceFactory = { _ in captureDeviceMock }
|
|
let cam = CameraTestUtils.createTestCamera(configuration)
|
|
|
|
let filePath = "test"
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate =
|
|
cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
// Completion runs on IO queue.
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(filePath, nil)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
// `Camera.captureToFile` runs on capture session queue.
|
|
captureSessionQueue.async {
|
|
cam.setFlashMode(.torch) { _ in }
|
|
cam.captureToFile { result in
|
|
if let result = self.assertSuccess(result) {
|
|
XCTAssertEqual(result, filePath)
|
|
}
|
|
pathExpectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
|
|
func testCaptureToFile_mustSavePhotoToCameraPicturesDirectory() {
|
|
let expectedPath = "/tmp/camera/pictures/"
|
|
let expectation = self.expectation(
|
|
description: "Photo must be saved to \(expectedPath) directory.")
|
|
|
|
let captureSessionQueue = DispatchQueue(label: "capture_session_queue")
|
|
captureSessionQueue.setSpecific(
|
|
key: captureSessionQueueSpecificKey, value: captureSessionQueueSpecificValue)
|
|
let cam = createCam(with: captureSessionQueue)
|
|
|
|
let mockOutput = MockCapturePhotoOutput()
|
|
mockOutput.capturePhotoWithSettingsStub = { settings, photoDelegate in
|
|
let delegate = cam.inProgressSavePhotoDelegates[settings.uniqueID]
|
|
let ioQueue = DispatchQueue(label: "io_queue")
|
|
ioQueue.async {
|
|
delegate?.completionHandler(delegate?.filePath, nil)
|
|
}
|
|
}
|
|
cam.capturePhotoOutput = mockOutput
|
|
|
|
captureSessionQueue.async {
|
|
cam.captureToFile { result in
|
|
if let filePath = self.assertSuccess(result) {
|
|
XCTAssertTrue(
|
|
filePath.contains(expectedPath)
|
|
)
|
|
}
|
|
expectation.fulfill()
|
|
}
|
|
}
|
|
|
|
waitForExpectations(timeout: 30, handler: nil)
|
|
}
|
|
}
|