798 lines
27 KiB
Dart
798 lines
27 KiB
Dart
// 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 'dart:async';
|
|
import 'dart:math';
|
|
|
|
import 'package:async/async.dart';
|
|
import 'package:camera_avfoundation/src/avfoundation_camera.dart';
|
|
import 'package:camera_avfoundation/src/messages.g.dart';
|
|
import 'package:camera_avfoundation/src/utils.dart';
|
|
import 'package:camera_platform_interface/camera_platform_interface.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter/widgets.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:mockito/annotations.dart';
|
|
import 'package:mockito/mockito.dart';
|
|
|
|
import 'avfoundation_camera_test.mocks.dart';
|
|
|
|
@GenerateNiceMocks(<MockSpec<Object>>[MockSpec<CameraApi>()])
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test('registers instance', () async {
|
|
AVFoundationCamera.registerWith();
|
|
expect(CameraPlatform.instance, isA<AVFoundationCamera>());
|
|
});
|
|
|
|
group('Creation, Initialization & Disposal Tests', () {
|
|
test('Should send creation data and receive back a camera id', () async {
|
|
// Arrange
|
|
final mockApi = MockCameraApi();
|
|
when(mockApi.create(any, any)).thenAnswer((_) async => 1);
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
const cameraName = 'Test';
|
|
|
|
// Act
|
|
final int cameraId = await camera.createCamera(
|
|
const CameraDescription(
|
|
name: cameraName,
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
);
|
|
|
|
// Assert
|
|
final VerificationResult verification = verify(mockApi.create(captureAny, captureAny));
|
|
expect(verification.captured[0], cameraName);
|
|
final settings = verification.captured[1] as PlatformMediaSettings?;
|
|
expect(settings, isNotNull);
|
|
expect(settings?.resolutionPreset, PlatformResolutionPreset.high);
|
|
expect(cameraId, 1);
|
|
});
|
|
|
|
test(
|
|
'Should send creation data and receive back a camera id using createCameraWithSettings',
|
|
() async {
|
|
// Arrange
|
|
final mockApi = MockCameraApi();
|
|
when(mockApi.create(any, any)).thenAnswer((_) async => 1);
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
const cameraName = 'Test';
|
|
const fps = 15;
|
|
const videoBitrate = 200000;
|
|
const audioBitrate = 32000;
|
|
|
|
// Act
|
|
final int cameraId = await camera.createCameraWithSettings(
|
|
const CameraDescription(
|
|
name: cameraName,
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
const MediaSettings(
|
|
resolutionPreset: ResolutionPreset.low,
|
|
fps: fps,
|
|
videoBitrate: videoBitrate,
|
|
audioBitrate: audioBitrate,
|
|
enableAudio: true,
|
|
),
|
|
);
|
|
|
|
// Assert
|
|
final VerificationResult verification = verify(mockApi.create(captureAny, captureAny));
|
|
expect(verification.captured[0], cameraName);
|
|
final settings = verification.captured[1] as PlatformMediaSettings?;
|
|
expect(settings, isNotNull);
|
|
expect(settings?.resolutionPreset, PlatformResolutionPreset.low);
|
|
expect(settings?.framesPerSecond, fps);
|
|
expect(settings?.videoBitrate, videoBitrate);
|
|
expect(settings?.audioBitrate, audioBitrate);
|
|
expect(settings?.enableAudio, true);
|
|
expect(cameraId, 1);
|
|
},
|
|
);
|
|
|
|
test('Should throw CameraException when create throws a PlatformException', () {
|
|
// Arrange
|
|
const exceptionCode = 'TESTING_ERROR_CODE';
|
|
const exceptionMessage = 'Mock error message used during testing.';
|
|
final mockApi = MockCameraApi();
|
|
when(mockApi.create(any, any)).thenAnswer((_) async {
|
|
throw PlatformException(code: exceptionCode, message: exceptionMessage);
|
|
});
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
|
|
// Act
|
|
expect(
|
|
() => camera.createCamera(
|
|
const CameraDescription(
|
|
name: 'Test',
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
),
|
|
throwsA(
|
|
isA<CameraException>()
|
|
.having((CameraException e) => e.code, 'code', exceptionCode)
|
|
.having((CameraException e) => e.description, 'description', exceptionMessage),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Should throw CameraException when initialize throws a PlatformException', () {
|
|
// Arrange
|
|
const exceptionCode = 'TESTING_ERROR_CODE';
|
|
const exceptionMessage = 'Mock error message used during testing.';
|
|
final mockApi = MockCameraApi();
|
|
when(mockApi.initialize(any, any)).thenAnswer((_) async {
|
|
throw PlatformException(code: exceptionCode, message: exceptionMessage);
|
|
});
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
|
|
// Act
|
|
expect(
|
|
() => camera.initializeCamera(0),
|
|
throwsA(
|
|
isA<CameraException>()
|
|
.having((CameraException e) => e.code, 'code', 'TESTING_ERROR_CODE')
|
|
.having(
|
|
(CameraException e) => e.description,
|
|
'description',
|
|
'Mock error message used during testing.',
|
|
),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Should send initialization data', () async {
|
|
// Arrange
|
|
final mockApi = MockCameraApi();
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
final int cameraId = await camera.createCamera(
|
|
const CameraDescription(
|
|
name: 'Test',
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
);
|
|
|
|
// Act
|
|
final Future<void> initializeFuture = camera.initializeCamera(cameraId);
|
|
camera.cameraEventStreamController.add(
|
|
CameraInitializedEvent(cameraId, 1920, 1080, ExposureMode.auto, true, FocusMode.auto, true),
|
|
);
|
|
await initializeFuture;
|
|
|
|
// Assert
|
|
final VerificationResult verification = verify(mockApi.initialize(captureAny, captureAny));
|
|
expect(verification.captured[0], cameraId);
|
|
// The default when unspecified should be bgra8888.
|
|
expect(verification.captured[1], PlatformImageFormatGroup.bgra8888);
|
|
});
|
|
|
|
test('Should send a disposal call on dispose', () async {
|
|
// Arrange
|
|
final mockApi = MockCameraApi();
|
|
final camera = AVFoundationCamera(api: mockApi);
|
|
final int cameraId = await camera.createCamera(
|
|
const CameraDescription(
|
|
name: 'Test',
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
);
|
|
final Future<void> initializeFuture = camera.initializeCamera(cameraId);
|
|
camera.cameraEventStreamController.add(
|
|
CameraInitializedEvent(cameraId, 1920, 1080, ExposureMode.auto, true, FocusMode.auto, true),
|
|
);
|
|
await initializeFuture;
|
|
|
|
// Act
|
|
await camera.dispose(cameraId);
|
|
|
|
// Assert
|
|
final VerificationResult verification = verify(mockApi.dispose(captureAny));
|
|
expect(verification.captured[0], cameraId);
|
|
});
|
|
});
|
|
|
|
group('Event Tests', () {
|
|
late AVFoundationCamera camera;
|
|
late int cameraId;
|
|
setUp(() async {
|
|
final mockApi = MockCameraApi();
|
|
when(mockApi.create(any, any)).thenAnswer((_) async => 1);
|
|
camera = AVFoundationCamera(api: mockApi);
|
|
cameraId = await camera.createCamera(
|
|
const CameraDescription(
|
|
name: 'Test',
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
);
|
|
final Future<void> initializeFuture = camera.initializeCamera(cameraId);
|
|
camera.cameraEventStreamController.add(
|
|
CameraInitializedEvent(cameraId, 1920, 1080, ExposureMode.auto, true, FocusMode.auto, true),
|
|
);
|
|
await initializeFuture;
|
|
});
|
|
|
|
test('Should receive initialized event', () async {
|
|
// Act
|
|
final Stream<CameraInitializedEvent> eventStream = camera.onCameraInitialized(cameraId);
|
|
final streamQueue = StreamQueue<CameraInitializedEvent>(eventStream);
|
|
|
|
final previewSize = PlatformSize(width: 3840, height: 2160);
|
|
// Emit test events
|
|
final event = CameraInitializedEvent(
|
|
cameraId,
|
|
previewSize.width,
|
|
previewSize.height,
|
|
ExposureMode.auto,
|
|
true,
|
|
FocusMode.auto,
|
|
true,
|
|
);
|
|
camera.hostCameraHandlers[cameraId]!.initialized(
|
|
PlatformCameraState(
|
|
previewSize: previewSize,
|
|
exposureMode: PlatformExposureMode.auto,
|
|
focusMode: PlatformFocusMode.auto,
|
|
exposurePointSupported: true,
|
|
focusPointSupported: true,
|
|
),
|
|
);
|
|
|
|
// Assert
|
|
expect(await streamQueue.next, event);
|
|
|
|
// Clean up
|
|
await streamQueue.cancel();
|
|
});
|
|
|
|
test('Should receive camera error events', () async {
|
|
// Act
|
|
final Stream<CameraErrorEvent> errorStream = camera.onCameraError(cameraId);
|
|
final streamQueue = StreamQueue<CameraErrorEvent>(errorStream);
|
|
|
|
// Emit test events
|
|
const errorMessage = 'Error Description';
|
|
final event = CameraErrorEvent(cameraId, errorMessage);
|
|
camera.hostCameraHandlers[cameraId]!.error(errorMessage);
|
|
camera.hostCameraHandlers[cameraId]!.error(errorMessage);
|
|
camera.hostCameraHandlers[cameraId]!.error(errorMessage);
|
|
|
|
// Assert
|
|
expect(await streamQueue.next, event);
|
|
expect(await streamQueue.next, event);
|
|
expect(await streamQueue.next, event);
|
|
|
|
// Clean up
|
|
await streamQueue.cancel();
|
|
});
|
|
|
|
test('Should receive device orientation change events', () async {
|
|
// Act
|
|
final Stream<DeviceOrientationChangedEvent> eventStream = camera.onDeviceOrientationChanged();
|
|
final streamQueue = StreamQueue<DeviceOrientationChangedEvent>(eventStream);
|
|
|
|
// Emit test events
|
|
const event = DeviceOrientationChangedEvent(DeviceOrientation.portraitUp);
|
|
for (var i = 0; i < 3; i++) {
|
|
camera.hostHandler.deviceOrientationChanged(PlatformDeviceOrientation.portraitUp);
|
|
}
|
|
|
|
// Assert
|
|
expect(await streamQueue.next, event);
|
|
expect(await streamQueue.next, event);
|
|
expect(await streamQueue.next, event);
|
|
|
|
// Clean up
|
|
await streamQueue.cancel();
|
|
});
|
|
});
|
|
|
|
group('Function Tests', () {
|
|
late MockCameraApi mockApi;
|
|
late AVFoundationCamera camera;
|
|
late int cameraId;
|
|
|
|
setUp(() async {
|
|
mockApi = MockCameraApi();
|
|
when(mockApi.create(any, any)).thenAnswer((_) async => 1);
|
|
camera = AVFoundationCamera(api: mockApi);
|
|
cameraId = await camera.createCamera(
|
|
const CameraDescription(
|
|
name: 'Test',
|
|
lensDirection: CameraLensDirection.back,
|
|
sensorOrientation: 0,
|
|
),
|
|
ResolutionPreset.high,
|
|
);
|
|
final Future<void> initializeFuture = camera.initializeCamera(cameraId);
|
|
camera.cameraEventStreamController.add(
|
|
CameraInitializedEvent(cameraId, 1920, 1080, ExposureMode.auto, true, FocusMode.auto, true),
|
|
);
|
|
await initializeFuture;
|
|
});
|
|
|
|
test('Should fetch CameraDescription instances for available cameras', () async {
|
|
final returnData = <PlatformCameraDescription>[
|
|
PlatformCameraDescription(
|
|
name: 'Test 1',
|
|
lensDirection: PlatformCameraLensDirection.front,
|
|
lensType: PlatformCameraLensType.ultraWide,
|
|
),
|
|
PlatformCameraDescription(
|
|
name: 'Test 2',
|
|
lensDirection: PlatformCameraLensDirection.back,
|
|
lensType: PlatformCameraLensType.telephoto,
|
|
),
|
|
];
|
|
when(mockApi.getAvailableCameras()).thenAnswer((_) async => returnData);
|
|
|
|
final List<CameraDescription> cameras = await camera.availableCameras();
|
|
|
|
expect(cameras.length, returnData.length);
|
|
for (var i = 0; i < returnData.length; i++) {
|
|
expect(cameras[i].name, returnData[i].name);
|
|
expect(
|
|
cameras[i].lensDirection,
|
|
cameraLensDirectionFromPlatform(returnData[i].lensDirection),
|
|
);
|
|
expect(cameras[i].lensType, cameraLensTypeFromPlatform(returnData[i].lensType));
|
|
// This value isn't provided by the platform, so is hard-coded to 90.
|
|
expect(cameras[i].sensorOrientation, 90);
|
|
}
|
|
});
|
|
|
|
test('Should throw CameraException when availableCameras throws a PlatformException', () {
|
|
const code = 'TESTING_ERROR_CODE';
|
|
const message = 'Mock error message used during testing.';
|
|
when(
|
|
mockApi.getAvailableCameras(),
|
|
).thenAnswer((_) async => throw PlatformException(code: code, message: message));
|
|
|
|
expect(
|
|
camera.availableCameras,
|
|
throwsA(
|
|
isA<CameraException>()
|
|
.having((CameraException e) => e.code, 'code', code)
|
|
.having((CameraException e) => e.description, 'description', message),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Should take a picture and return an XFile instance', () async {
|
|
const stubPath = '/test/path.jpg';
|
|
when(mockApi.takePicture()).thenAnswer((_) async => stubPath);
|
|
|
|
final XFile file = await camera.takePicture(cameraId);
|
|
|
|
expect(file.path, stubPath);
|
|
});
|
|
|
|
test('Should prepare for video recording', () async {
|
|
await camera.prepareForVideoRecording();
|
|
|
|
verify(mockApi.prepareForVideoRecording());
|
|
});
|
|
|
|
test('Should start recording a video', () async {
|
|
await camera.startVideoRecording(cameraId);
|
|
|
|
verify(mockApi.startVideoRecording(any));
|
|
});
|
|
|
|
test(
|
|
'Should pass enableStream if callback is passed when starting recording a video',
|
|
() async {
|
|
await camera.startVideoCapturing(
|
|
VideoCaptureOptions(cameraId, streamCallback: (CameraImageData imageData) {}),
|
|
);
|
|
|
|
verify(mockApi.startVideoRecording(true));
|
|
},
|
|
);
|
|
|
|
test('Should stop a video recording and return the file', () async {
|
|
const stubPath = '/test/path.mp4';
|
|
when(mockApi.stopVideoRecording()).thenAnswer((_) async => stubPath);
|
|
|
|
final XFile file = await camera.stopVideoRecording(cameraId);
|
|
|
|
expect(file.path, stubPath);
|
|
});
|
|
|
|
test('Should pause a video recording', () async {
|
|
await camera.pauseVideoRecording(cameraId);
|
|
|
|
verify(mockApi.pauseVideoRecording());
|
|
});
|
|
|
|
test('Should resume a video recording', () async {
|
|
await camera.resumeVideoRecording(cameraId);
|
|
|
|
verify(mockApi.resumeVideoRecording());
|
|
});
|
|
|
|
test('Should set the description while recording', () async {
|
|
const camera2Description = CameraDescription(
|
|
name: 'Test2',
|
|
lensDirection: CameraLensDirection.front,
|
|
sensorOrientation: 0,
|
|
);
|
|
|
|
await camera.setDescriptionWhileRecording(camera2Description);
|
|
|
|
verify(mockApi.updateDescriptionWhileRecording(camera2Description.name));
|
|
});
|
|
|
|
test('Should set the flash mode to torch', () async {
|
|
await camera.setFlashMode(cameraId, FlashMode.torch);
|
|
|
|
verify(mockApi.setFlashMode(PlatformFlashMode.torch));
|
|
});
|
|
|
|
test('Should set the flash mode to always', () async {
|
|
await camera.setFlashMode(cameraId, FlashMode.always);
|
|
|
|
verify(mockApi.setFlashMode(PlatformFlashMode.always));
|
|
});
|
|
|
|
test('Should set the flash mode to auto', () async {
|
|
await camera.setFlashMode(cameraId, FlashMode.auto);
|
|
|
|
verify(mockApi.setFlashMode(PlatformFlashMode.auto));
|
|
});
|
|
|
|
test('Should set the flash mode to off', () async {
|
|
await camera.setFlashMode(cameraId, FlashMode.off);
|
|
|
|
verify(mockApi.setFlashMode(PlatformFlashMode.off));
|
|
});
|
|
|
|
test('Should set the exposure mode to auto', () async {
|
|
await camera.setExposureMode(cameraId, ExposureMode.auto);
|
|
|
|
verify(mockApi.setExposureMode(PlatformExposureMode.auto));
|
|
});
|
|
|
|
test('Should set the exposure mode to locked', () async {
|
|
await camera.setExposureMode(cameraId, ExposureMode.locked);
|
|
|
|
verify(mockApi.setExposureMode(PlatformExposureMode.locked));
|
|
});
|
|
|
|
test('Should set the exposure point to a value', () async {
|
|
const point = Point<double>(0.4, 0.6);
|
|
await camera.setExposurePoint(cameraId, point);
|
|
|
|
final VerificationResult verification = verify(mockApi.setExposurePoint(captureAny));
|
|
final passedPoint = verification.captured[0] as PlatformPoint?;
|
|
expect(passedPoint?.x, point.x);
|
|
expect(passedPoint?.y, point.y);
|
|
});
|
|
|
|
test('Should set the exposure point to null for reset', () async {
|
|
await camera.setExposurePoint(cameraId, null);
|
|
|
|
final VerificationResult verification = verify(mockApi.setExposurePoint(captureAny));
|
|
final passedPoint = verification.captured[0] as PlatformPoint?;
|
|
expect(passedPoint, null);
|
|
});
|
|
|
|
test('Should get the min exposure offset', () async {
|
|
const stubMinOffset = 2.0;
|
|
when(mockApi.getMinExposureOffset()).thenAnswer((_) async => stubMinOffset);
|
|
|
|
final double minExposureOffset = await camera.getMinExposureOffset(cameraId);
|
|
|
|
expect(minExposureOffset, stubMinOffset);
|
|
});
|
|
|
|
test('Should get the max exposure offset', () async {
|
|
const stubMaxOffset = 2.0;
|
|
when(mockApi.getMaxExposureOffset()).thenAnswer((_) async => stubMaxOffset);
|
|
|
|
final double maxExposureOffset = await camera.getMaxExposureOffset(cameraId);
|
|
|
|
expect(maxExposureOffset, stubMaxOffset);
|
|
});
|
|
|
|
test('Exposure offset step size should always return zero', () async {
|
|
final double stepSize = await camera.getExposureOffsetStepSize(cameraId);
|
|
|
|
expect(stepSize, 0.0);
|
|
});
|
|
|
|
test('Should set the exposure offset', () async {
|
|
const stubOffset = 0.5;
|
|
final double actualOffset = await camera.setExposureOffset(cameraId, 0.5);
|
|
|
|
verify(mockApi.setExposureOffset(stubOffset));
|
|
// iOS never adjusts the offset.
|
|
expect(actualOffset, stubOffset);
|
|
});
|
|
|
|
test('Should set the focus mode to auto', () async {
|
|
await camera.setFocusMode(cameraId, FocusMode.auto);
|
|
|
|
verify(mockApi.setFocusMode(PlatformFocusMode.auto));
|
|
});
|
|
|
|
test('Should set the focus mode to locked', () async {
|
|
await camera.setFocusMode(cameraId, FocusMode.locked);
|
|
|
|
verify(mockApi.setFocusMode(PlatformFocusMode.locked));
|
|
});
|
|
|
|
test('Should set the focus point to a value', () async {
|
|
const point = Point<double>(0.4, 0.6);
|
|
await camera.setFocusPoint(cameraId, point);
|
|
|
|
final VerificationResult verification = verify(mockApi.setFocusPoint(captureAny));
|
|
final passedPoint = verification.captured[0] as PlatformPoint?;
|
|
expect(passedPoint?.x, point.x);
|
|
expect(passedPoint?.y, point.y);
|
|
});
|
|
|
|
test('Should set the focus point to null for reset', () async {
|
|
await camera.setFocusPoint(cameraId, null);
|
|
|
|
final VerificationResult verification = verify(mockApi.setFocusPoint(captureAny));
|
|
final passedPoint = verification.captured[0] as PlatformPoint?;
|
|
expect(passedPoint, null);
|
|
});
|
|
|
|
test('Should build a texture widget as preview widget', () async {
|
|
final Widget widget = camera.buildPreview(cameraId);
|
|
|
|
expect(widget is Texture, isTrue);
|
|
expect((widget as Texture).textureId, cameraId);
|
|
});
|
|
|
|
test('Should get the max zoom level', () async {
|
|
const stubZoomLevel = 10.0;
|
|
when(mockApi.getMaxZoomLevel()).thenAnswer((_) async => stubZoomLevel);
|
|
|
|
final double maxZoomLevel = await camera.getMaxZoomLevel(cameraId);
|
|
|
|
expect(maxZoomLevel, stubZoomLevel);
|
|
});
|
|
|
|
test('Should get the min zoom level', () async {
|
|
const stubZoomLevel = 10.0;
|
|
when(mockApi.getMinZoomLevel()).thenAnswer((_) async => stubZoomLevel);
|
|
|
|
final double minZoomLevel = await camera.getMinZoomLevel(cameraId);
|
|
|
|
expect(minZoomLevel, stubZoomLevel);
|
|
});
|
|
|
|
test('Should set the zoom level', () async {
|
|
const zoom = 2.0;
|
|
|
|
await camera.setZoomLevel(cameraId, zoom);
|
|
|
|
verify(mockApi.setZoomLevel(zoom));
|
|
});
|
|
|
|
test('Should throw CameraException when illegal zoom level is supplied', () async {
|
|
const code = 'ZOOM_ERROR';
|
|
const message = 'Illegal zoom error';
|
|
when(
|
|
mockApi.setZoomLevel(any),
|
|
).thenAnswer((_) async => throw PlatformException(code: code, message: message));
|
|
|
|
expect(
|
|
() => camera.setZoomLevel(cameraId, -1.0),
|
|
throwsA(
|
|
isA<CameraException>()
|
|
.having((CameraException e) => e.code, 'code', code)
|
|
.having((CameraException e) => e.description, 'description', message),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Should set video stabilization mode to off', () async {
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.off),
|
|
).thenAnswer((_) async => true);
|
|
|
|
await camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.off);
|
|
|
|
verify(mockApi.setVideoStabilizationMode(PlatformVideoStabilizationMode.off));
|
|
});
|
|
|
|
test('Should set video stabilization mode to level1', () async {
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.standard),
|
|
).thenAnswer((_) async => true);
|
|
|
|
await camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level1);
|
|
|
|
verify(mockApi.setVideoStabilizationMode(PlatformVideoStabilizationMode.standard));
|
|
});
|
|
|
|
test('Should set video stabilization mode to cinematic', () async {
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.cinematic),
|
|
).thenAnswer((_) async => true);
|
|
|
|
await camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level2);
|
|
|
|
verify(mockApi.setVideoStabilizationMode(PlatformVideoStabilizationMode.cinematic));
|
|
});
|
|
|
|
test('Should set video stabilization mode to cinematicExtended', () async {
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.cinematicExtended),
|
|
).thenAnswer((_) async => true);
|
|
|
|
await camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level3);
|
|
|
|
verify(mockApi.setVideoStabilizationMode(PlatformVideoStabilizationMode.cinematicExtended));
|
|
});
|
|
|
|
test('Should get no video stabilization mode', () async {
|
|
when(mockApi.isVideoStabilizationModeSupported(any)).thenAnswer((_) async => false);
|
|
|
|
final Iterable<VideoStabilizationMode> modes = await camera
|
|
.getSupportedVideoStabilizationModes(cameraId);
|
|
|
|
expect(modes, isEmpty);
|
|
});
|
|
|
|
test('Should get off and standard video stabilization modes', () async {
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.off),
|
|
).thenAnswer((_) async => true);
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.standard),
|
|
).thenAnswer((_) async => true);
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.cinematic),
|
|
).thenAnswer((_) async => false);
|
|
when(
|
|
mockApi.isVideoStabilizationModeSupported(PlatformVideoStabilizationMode.cinematicExtended),
|
|
).thenAnswer((_) async => false);
|
|
|
|
final List<VideoStabilizationMode> modes = (await camera.getSupportedVideoStabilizationModes(
|
|
cameraId,
|
|
)).toList();
|
|
|
|
expect(modes, <VideoStabilizationMode>[
|
|
VideoStabilizationMode.off,
|
|
VideoStabilizationMode.level1,
|
|
]);
|
|
});
|
|
|
|
test('Should get all video stabilization modes', () async {
|
|
when(mockApi.isVideoStabilizationModeSupported(any)).thenAnswer((_) async => true);
|
|
|
|
final List<VideoStabilizationMode> modes = (await camera.getSupportedVideoStabilizationModes(
|
|
cameraId,
|
|
)).toList();
|
|
|
|
expect(modes, <VideoStabilizationMode>[
|
|
VideoStabilizationMode.off,
|
|
VideoStabilizationMode.level1,
|
|
VideoStabilizationMode.level2,
|
|
VideoStabilizationMode.level3,
|
|
]);
|
|
});
|
|
|
|
test('Should throw ArgumentError when unavailable video stabilization mode is set', () async {
|
|
when(mockApi.isVideoStabilizationModeSupported(any)).thenAnswer((_) async => false);
|
|
|
|
expect(
|
|
() => camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.off),
|
|
throwsA(isA<ArgumentError>().having((ArgumentError e) => e.name, 'name', 'mode')),
|
|
);
|
|
expect(
|
|
() => camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level1),
|
|
throwsA(isA<ArgumentError>().having((ArgumentError e) => e.name, 'name', 'mode')),
|
|
);
|
|
expect(
|
|
() => camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level2),
|
|
throwsA(isA<ArgumentError>().having((ArgumentError e) => e.name, 'name', 'mode')),
|
|
);
|
|
expect(
|
|
() => camera.setVideoStabilizationMode(cameraId, VideoStabilizationMode.level3),
|
|
throwsA(isA<ArgumentError>().having((ArgumentError e) => e.name, 'name', 'mode')),
|
|
);
|
|
});
|
|
|
|
test('Should throw CameraException when illegal zoom level is supplied', () async {
|
|
const code = 'ZOOM_ERROR';
|
|
const message = 'Illegal zoom error';
|
|
when(
|
|
mockApi.setZoomLevel(any),
|
|
).thenAnswer((_) async => throw PlatformException(code: code, message: message));
|
|
|
|
expect(
|
|
() => camera.setZoomLevel(cameraId, -1.0),
|
|
throwsA(
|
|
isA<CameraException>()
|
|
.having((CameraException e) => e.code, 'code', code)
|
|
.having((CameraException e) => e.description, 'description', message),
|
|
),
|
|
);
|
|
});
|
|
|
|
test('Should lock the capture orientation', () async {
|
|
await camera.lockCaptureOrientation(cameraId, DeviceOrientation.portraitUp);
|
|
|
|
verify(mockApi.lockCaptureOrientation(PlatformDeviceOrientation.portraitUp));
|
|
});
|
|
|
|
test('Should unlock the capture orientation', () async {
|
|
await camera.unlockCaptureOrientation(cameraId);
|
|
|
|
verify(mockApi.unlockCaptureOrientation());
|
|
});
|
|
|
|
test('Should pause the camera preview', () async {
|
|
await camera.pausePreview(cameraId);
|
|
|
|
verify(mockApi.pausePreview());
|
|
});
|
|
|
|
test('Should resume the camera preview', () async {
|
|
await camera.resumePreview(cameraId);
|
|
|
|
verify(mockApi.resumePreview());
|
|
});
|
|
|
|
test('Should report support for image streaming', () async {
|
|
expect(camera.supportsImageStreaming(), true);
|
|
});
|
|
|
|
test('Should start streaming', () async {
|
|
final StreamSubscription<CameraImageData> subscription = camera
|
|
.onStreamedFrameAvailable(cameraId)
|
|
.listen((CameraImageData imageData) {});
|
|
|
|
verify(mockApi.startImageStream());
|
|
|
|
await subscription.cancel();
|
|
});
|
|
|
|
test('Should stop streaming', () async {
|
|
final StreamSubscription<CameraImageData> subscription = camera
|
|
.onStreamedFrameAvailable(cameraId)
|
|
.listen((CameraImageData imageData) {});
|
|
await subscription.cancel();
|
|
|
|
verify(mockApi.startImageStream());
|
|
verify(mockApi.stopImageStream());
|
|
});
|
|
|
|
test('Should set the ImageFileFormat to heif', () async {
|
|
await camera.setImageFileFormat(cameraId, ImageFileFormat.heif);
|
|
|
|
verify(mockApi.setImageFileFormat(PlatformImageFileFormat.heif));
|
|
});
|
|
|
|
test('Should set the ImageFileFormat to jpeg', () async {
|
|
await camera.setImageFileFormat(cameraId, ImageFileFormat.jpeg);
|
|
|
|
verify(mockApi.setImageFileFormat(PlatformImageFileFormat.jpeg));
|
|
});
|
|
|
|
test('Should set the image quality', () async {
|
|
await camera.setJpegImageQuality(cameraId, 50);
|
|
|
|
verify(mockApi.setJpegImageQuality(50));
|
|
});
|
|
});
|
|
}
|