- 新增 setActivePort 方法用于在同一USB设备内部切换活跃串口 - 新增 requestUsbPermission 方法用于主动申请指定设备的USB权限 - 实现Android侧USB权限申请广播接收器和同步等待机制 - 在示例应用中集成权限预申请和端口切换UI逻辑 - 优化设备打开后自动拉取真实串口列表的功能 - 更新端口选择下拉框在打开状态下支持实时切换串口
162 lines
4.6 KiB
Dart
162 lines
4.6 KiB
Dart
import 'dart:typed_data';
|
|
|
|
import 'package:ch934x_serial/ch934x_serial.dart';
|
|
import 'package:ch934x_serial/ch934x_serial_method_channel.dart';
|
|
import 'package:ch934x_serial/ch934x_serial_platform_interface.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_test/flutter_test.dart';
|
|
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
|
|
|
|
/// 用 mock 替代真实平台,以便在宿主测试中验证上层调用。
|
|
class _MockCh934xSerialPlatform extends Ch934xSerialPlatform
|
|
with MockPlatformInterfaceMixin {
|
|
_MockCh934xSerialPlatform({
|
|
// ignore: unused_element_parameter
|
|
this.deviceList = const <Ch934xDeviceInfo>[],
|
|
// ignore: unused_element_parameter
|
|
this.serialNumber,
|
|
// ignore: unused_element_parameter
|
|
this.deviceType = Ch934xDeviceType.ch9344,
|
|
// ignore: unused_element_parameter
|
|
this.ports = const <Ch934xSerialPortInfo>[],
|
|
// ignore: unused_element_parameter
|
|
this.openResult = true,
|
|
// ignore: unused_element_parameter
|
|
this.closeResult = true,
|
|
// ignore: unused_element_parameter
|
|
this.readBytes,
|
|
// ignore: unused_element_parameter
|
|
this.writeResult = 0,
|
|
// ignore: unused_element_parameter
|
|
this.gpioOutputResult = true,
|
|
// ignore: unused_element_parameter
|
|
this.gpioInput = 1,
|
|
// ignore: unused_element_parameter
|
|
this.modemControlResult = true,
|
|
// ignore: unused_element_parameter
|
|
this.modemStatus = ModemStatus.cts,
|
|
});
|
|
|
|
List<Ch934xDeviceInfo> deviceList;
|
|
String? serialNumber;
|
|
int deviceType;
|
|
List<Ch934xSerialPortInfo> ports;
|
|
bool openResult;
|
|
bool closeResult;
|
|
Uint8List? readBytes;
|
|
int writeResult;
|
|
bool gpioOutputResult;
|
|
int gpioInput;
|
|
bool modemControlResult;
|
|
int modemStatus;
|
|
|
|
@override
|
|
Future<List<Ch934xDeviceInfo>> getDeviceList() async => deviceList;
|
|
|
|
@override
|
|
Future<String?> getSerialNumber(int deviceId) async => serialNumber;
|
|
|
|
@override
|
|
Future<int> getDeviceType(int deviceId) async => deviceType;
|
|
|
|
@override
|
|
Future<List<Ch934xSerialPortInfo>> getSerialPortList(
|
|
int deviceId, {
|
|
required int interfaceNumber,
|
|
}) async =>
|
|
ports;
|
|
|
|
@override
|
|
Future<bool> openPort(Ch934xPortTarget target) async => openResult;
|
|
|
|
@override
|
|
Future<bool> closePort() async => closeResult;
|
|
|
|
@override
|
|
Future<bool> setActivePort(int serialPortIndex) async => true;
|
|
|
|
@override
|
|
Future<bool> requestUsbPermission(int deviceId) async => true;
|
|
|
|
@override
|
|
Future<Uint8List> read(int length) async => readBytes ?? Uint8List(0);
|
|
|
|
@override
|
|
Future<int> write(Uint8List data) async => writeResult;
|
|
|
|
@override
|
|
Future<bool> setGpioOutput({
|
|
required int gpioNumber,
|
|
required int level,
|
|
}) async =>
|
|
gpioOutputResult;
|
|
|
|
@override
|
|
Future<int> getGpioInput(int gpioNumber) async => gpioInput;
|
|
|
|
@override
|
|
Future<bool> setModemControl({required int dtr, required int rts}) async =>
|
|
modemControlResult;
|
|
|
|
@override
|
|
Future<int> getModemStatus() async => modemStatus;
|
|
|
|
@override
|
|
Future<void> setExceptionCallback(
|
|
void Function(Ch934xException exception) onException,
|
|
) async {}
|
|
}
|
|
|
|
void main() {
|
|
TestWidgetsFlutterBinding.ensureInitialized();
|
|
|
|
test('默认平台实现是 MethodChannelCh934xSerial', () {
|
|
expect(Ch934xSerialPlatform.instance, isInstanceOf<MethodChannelCh934xSerial>());
|
|
});
|
|
|
|
test('Ch934xSerial 委托 platform 调用 getDeviceList', () async {
|
|
final mock = _MockCh934xSerialPlatform(
|
|
deviceList: const [
|
|
Ch934xDeviceInfo(
|
|
deviceId: 1,
|
|
vendorId: 0x1a86,
|
|
productId: 0xfe0c,
|
|
deviceType: Ch934xDeviceType.ch9344,
|
|
serialNumber: 'SN-1',
|
|
),
|
|
],
|
|
);
|
|
final plugin = Ch934xSerial.withPlatform(mock);
|
|
final list = await plugin.getDeviceList();
|
|
expect(list.single.serialNumber, 'SN-1');
|
|
});
|
|
|
|
test('ModemStatus.isSet 按位与工作', () {
|
|
const status = ModemStatus.cts | ModemStatus.dcd;
|
|
expect(ModemStatus.isSet(status, ModemStatus.cts), isTrue);
|
|
expect(ModemStatus.isSet(status, ModemStatus.dsr), isFalse);
|
|
});
|
|
|
|
test('Ch934xPortTarget.toMap 字段可被 MethodChannel 直接消费', () {
|
|
const target = Ch934xPortTarget(
|
|
deviceId: 2,
|
|
interfaceNumber: 1,
|
|
serialPortIndex: 3,
|
|
);
|
|
expect(target.toMap(), <String, Object>{
|
|
'deviceId': 2,
|
|
'interfaceNumber': 1,
|
|
'serialPortIndex': 3,
|
|
});
|
|
});
|
|
|
|
test('Ch934xException.toString 汇总关键字段', () {
|
|
final ex = Ch934xException(
|
|
type: Ch934xExceptionType.deviceDetached,
|
|
message: '设备被拔出',
|
|
);
|
|
expect(ex.toString(), contains('deviceDetached'));
|
|
expect(ex.toString(), contains('设备被拔出'));
|
|
});
|
|
}
|