Fix characteristic value listener and add tests (#168)

* Improve characteristic value listener

* Implement characteristic tests

* Bump version and update changelog
This commit is contained in:
Rohit Sangwan
2025-07-08 11:43:45 +05:30
committed by GitHub
parent d56851cbfb
commit 2170588045
6 changed files with 240 additions and 9 deletions
+127
View File
@@ -0,0 +1,127 @@
import 'dart:async';
import 'package:flutter/foundation.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:universal_ble/universal_ble.dart';
import 'universal_ble_test_mock.dart';
String serviceId = "180a";
String characteristicId = "202a";
String mockDeviceId = "mock_id";
BleCharacteristic mockBleCharacteristic = BleCharacteristic.withMetaData(
deviceId: mockDeviceId,
serviceId: serviceId,
uuid: characteristicId,
properties: CharacteristicProperty.values,
);
BleService mockBleService = BleService(serviceId, [mockBleCharacteristic]);
void main() {
late UniversalBlePlatform platform;
setUp(() {
platform = _UniversalBleMock();
UniversalBle.setInstance(platform);
});
group('BleCharacteristic Tests', () {
test("DiscoverServices test", () async {
debugPrint("Discovering services");
List<BleService> services =
await UniversalBle.discoverServices(mockDeviceId);
expect(services.length, 1);
BleService service = services.first;
expect(BleUuidParser.compareStrings(service.uuid, serviceId), true);
expect(service.characteristics.length, 1);
BleCharacteristic characteristic = service.characteristics.first;
expect(
BleUuidParser.compareStrings(characteristic.uuid, characteristicId),
true,
);
expect(characteristic.metaData?.deviceId, mockDeviceId);
expect(
BleUuidParser.compareStrings(
characteristic.metaData!.serviceId,
serviceId,
),
true,
);
});
test("Subscription Test", () async {
BleCharacteristic characteristic = mockBleCharacteristic;
debugPrint("Subscribing to char");
await characteristic.notifications.subscribe();
bool gotEvent = false;
var subscription = characteristic.notifications.listen((data) {
debugPrint("Received CharValue: $data");
gotEvent = true;
});
await Future.delayed(Duration(seconds: 1));
await characteristic.notifications.unsubscribe();
debugPrint("Unsubscribed from char");
subscription.cancel();
expect(gotEvent, true);
});
});
test("Write/Read Value Test", () async {
BleCharacteristic characteristic = mockBleCharacteristic;
Uint8List charValue = Uint8List.fromList([0x01, 0x02]);
await characteristic.write(charValue);
debugPrint("Write Succeed");
var readResult = await characteristic.read();
debugPrint("Read Succeed");
expect(readResult, charValue);
});
}
class _UniversalBleMock extends UniversalBlePlatformMock {
Timer? notifierTimer;
Uint8List? charValue;
@override
Future<List<BleService>> discoverServices(String deviceId) async {
return <BleService>[mockBleService];
}
@override
Future<void> setNotifiable(String deviceId, String service,
String characteristic, BleInputProperty bleInputProperty) async {
if (bleInputProperty == BleInputProperty.disabled) {
notifierTimer?.cancel();
notifierTimer = null;
return;
}
notifierTimer ??= Timer.periodic(Duration(milliseconds: 500), (timer) {
updateCharacteristicValue(
deviceId,
characteristic,
Uint8List.fromList([1, 2, 3]),
);
});
}
@override
Future<void> writeValue(
String deviceId,
String service,
String characteristic,
Uint8List value,
BleOutputProperty bleOutputProperty) async {
charValue = value;
}
@override
Future<Uint8List> readValue(
String deviceId, String service, String characteristic,
{Duration? timeout}) async {
return charValue ?? Uint8List(0);
}
}
+98
View File
@@ -0,0 +1,98 @@
import 'dart:typed_data';
import 'package:universal_ble/universal_ble.dart';
abstract class UniversalBlePlatformMock extends UniversalBlePlatform {
@override
Future<void> connect(String deviceId, {Duration? connectionTimeout}) {
throw UnimplementedError();
}
@override
Future<bool> disableBluetooth() {
throw UnimplementedError();
}
@override
Future<void> disconnect(String deviceId) {
throw UnimplementedError();
}
@override
Future<List<BleService>> discoverServices(String deviceId) {
throw UnimplementedError();
}
@override
Future<bool> enableBluetooth() {
throw UnimplementedError();
}
@override
Future<AvailabilityState> getBluetoothAvailabilityState() {
throw UnimplementedError();
}
@override
Future<BleConnectionState> getConnectionState(String deviceId) {
throw UnimplementedError();
}
@override
Future<List<BleDevice>> getSystemDevices(List<String>? withServices) {
throw UnimplementedError();
}
@override
Future<bool> isPaired(String deviceId) {
throw UnimplementedError();
}
@override
Future<bool> pair(String deviceId) {
throw UnimplementedError();
}
@override
Future<Uint8List> readValue(
String deviceId, String service, String characteristic,
{Duration? timeout}) {
throw UnimplementedError();
}
@override
Future<int> requestMtu(String deviceId, int expectedMtu) {
throw UnimplementedError();
}
@override
Future<void> setNotifiable(String deviceId, String service,
String characteristic, BleInputProperty bleInputProperty) {
throw UnimplementedError();
}
@override
Future<void> startScan(
{ScanFilter? scanFilter, PlatformConfig? platformConfig}) {
throw UnimplementedError();
}
@override
Future<void> stopScan() {
throw UnimplementedError();
}
@override
Future<void> unpair(String deviceId) {
throw UnimplementedError();
}
@override
Future<void> writeValue(
String deviceId,
String service,
String characteristic,
Uint8List value,
BleOutputProperty bleOutputProperty) {
throw UnimplementedError();
}
}