Files
biz_xfj_cloud/test/common/face_recognition_panel_test.dart
T
2026-08-06 20:55:09 +08:00

127 lines
3.8 KiB
Dart

import 'dart:async';
import 'package:ducafe_ui_core/ducafe_ui_core.dart';
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:forui/forui.dart';
import 'package:pj_supermarket_cloud/common/index.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
late int createTextureCount;
late int releaseTextureCount;
setUp(() {
createTextureCount = 0;
releaseTextureCount = 0;
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(FaceDiscernPlugs.getChannel, (call) async {
if (call.method == 'createPreviewTexture') {
createTextureCount++;
return <String, Object>{
'textureId': 42,
'width': 1280,
'height': 720,
'rotation': 0,
'mirror': true,
};
}
if (call.method == 'releasePreviewTexture') {
releaseTextureCount++;
}
return null;
});
});
tearDown(() {
TestDefaultBinaryMessengerBinding.instance.defaultBinaryMessenger
.setMockMethodCallHandler(FaceDiscernPlugs.getChannel, null);
});
testWidgets('面板销毁时取消事件监听、当前会话并释放预览纹理', (tester) async {
final eventController =
StreamController<FaceRecognitionSessionEvent>.broadcast();
addTearDown(eventController.close);
final resultCompleter = Completer<FaceStream>();
final service = _FakeFaceRecognitionSessionService('session-1');
final panelController = FaceRecognitionPanelController();
final handle = FaceRecognitionSessionHandle(
sessionId: 'session-1',
scene: FaceRecognitionScene.cashier,
events: eventController.stream,
result: resultCompleter.future,
);
await tester.pumpWidget(
_facePanelTestApp(
FaceRecognitionPanel(
service: service,
handle: handle,
controller: panelController,
onRecognized: (_) {},
timeout: const Duration(minutes: 1),
),
),
);
await tester.pump();
expect(createTextureCount, 1);
expect(eventController.hasListener, isTrue);
await tester.pumpWidget(_facePanelTestApp(const SizedBox.shrink()));
await tester.pump();
expect(eventController.hasListener, isFalse);
expect(service.cancelCount, 1);
expect(releaseTextureCount, 1);
await panelController.cancel();
expect(service.cancelCount, 1, reason: '销毁后的控制句柄不得继续操作旧会话');
expect(tester.takeException(), isNull);
});
}
/// 构建具备项目缩放和 ForUI 主题的人脸面板测试环境。
Widget _facePanelTestApp(Widget child) {
return ScreenUtilInit(
designSize: const Size(1920, 1080),
builder: (_, __) => MaterialApp(
home: FTheme(
data: FThemes.zinc.light,
child: Scaffold(body: Center(child: child)),
),
),
);
}
/// 测试专用人脸会话服务,只记录面板是否按所有权释放当前会话。
class _FakeFaceRecognitionSessionService extends FaceRecognitionSessionService {
/// 创建持有指定会话的测试服务。
_FakeFaceRecognitionSessionService(this.sessionId);
/// 当前测试服务拥有的会话 ID。
final String sessionId;
/// 面板销毁触发的取消次数。
int cancelCount = 0;
/// 当前测试会话是否仍归此服务所有。
bool active = true;
/// 仅声明与测试句柄一致的会话归属。
@override
bool owns(String? sessionId) => active && sessionId == this.sessionId;
/// 记录销毁时的取消动作并释放测试会话所有权。
@override
Future<void> cancel({String message = '已取消人脸识别'}) async {
cancelCount++;
active = false;
}
/// 结束路径与取消路径都释放测试会话所有权。
@override
Future<void> finish() async {
active = false;
}
}