2023-04-05 15:02:10 +02:00
|
|
|
using System;
|
2021-05-13 17:25:46 +02:00
|
|
|
using System.Collections.Generic;
|
2023-04-05 15:02:10 +02:00
|
|
|
using System.Threading;
|
2021-05-13 17:25:46 +02:00
|
|
|
using System.Threading.Tasks;
|
2022-08-30 15:42:25 +02:00
|
|
|
using NSubstitute;
|
|
|
|
using NUnit.Framework;
|
2023-04-05 15:02:10 +02:00
|
|
|
using Plugin.BLE.Abstractions.Contracts;
|
2024-04-09 12:53:23 +02:00
|
|
|
using ShareeBike.Services.BluetoothLock;
|
|
|
|
using ShareeBike.Services.BluetoothLock.BLE;
|
|
|
|
using ShareeBike.Services.BluetoothLock.Exception;
|
|
|
|
using ShareeBike.Services.BluetoothLock.Tdo;
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
namespace LockIt.BLE.Tests.Services.BluetoothLock.BLE
|
2021-05-13 17:25:46 +02:00
|
|
|
{
|
2022-09-06 16:08:19 +02:00
|
|
|
public class TestLockItServiceBase
|
|
|
|
{
|
|
|
|
[Test]
|
|
|
|
public async Task TestCheckReconnect_EmptyList()
|
|
|
|
{
|
|
|
|
var disconnectedDevice = Substitute.For<ILockService>();
|
|
|
|
disconnectedDevice.GetDeviceState().Returns(DeviceState.Disconnected);
|
|
|
|
var devices = new List<ILockService> { disconnectedDevice };
|
|
|
|
var locksInfo = new List<LockInfoAuthTdo>();
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await LockItServiceBase.CheckReconnect(
|
|
|
|
devices,
|
|
|
|
locksInfo,
|
|
|
|
TimeSpan.FromSeconds(0));
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await disconnectedDevice.DidNotReceive().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
|
|
|
}
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
[Test]
|
|
|
|
public async Task TestCheckReconnect_NoMatchingIdEntry()
|
|
|
|
{
|
|
|
|
var disconnectedDevice = Substitute.For<ILockService>();
|
|
|
|
disconnectedDevice.GetDeviceState().Returns(DeviceState.Disconnected);
|
|
|
|
disconnectedDevice.Name.Returns("ISHAREIT+334");
|
|
|
|
disconnectedDevice.Guid.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
var devices = new List<ILockService> { disconnectedDevice };
|
|
|
|
var locksInfo = new List<LockInfoAuthTdo> { new LockInfoAuthTdo.Builder { Id = 992, Guid = new Guid("00000000-0000-0000-0000-000000000002"), K_seed = new byte[] { 2 }, K_u = new byte[] { 3 } }.Build() };
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await LockItServiceBase.CheckReconnect(
|
|
|
|
devices,
|
|
|
|
locksInfo,
|
|
|
|
TimeSpan.FromSeconds(0));
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await disconnectedDevice.DidNotReceive().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
|
|
|
}
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
[Test]
|
|
|
|
public async Task TestCheckReconnect()
|
|
|
|
{
|
|
|
|
var disconnectedDevice = Substitute.For<ILockService>();
|
|
|
|
disconnectedDevice.GetDeviceState().Returns(DeviceState.Disconnected);
|
|
|
|
disconnectedDevice.Name.Returns("ISHAREIT+992");
|
|
|
|
disconnectedDevice.Guid.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
var devices = new List<ILockService> { disconnectedDevice };
|
|
|
|
var locksInfo = new List<LockInfoAuthTdo> { new LockInfoAuthTdo.Builder { Id = 992, Guid = new Guid("00000000-0000-0000-0000-000000000002"), K_seed = new byte[] { 2 }, K_u = new byte[] { 3 } }.Build() };
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await LockItServiceBase.CheckReconnect(
|
|
|
|
devices,
|
|
|
|
locksInfo,
|
|
|
|
TimeSpan.FromSeconds(0));
|
2021-05-13 17:25:46 +02:00
|
|
|
|
2022-09-06 16:08:19 +02:00
|
|
|
await disconnectedDevice.Received().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
|
|
|
}
|
2023-04-05 15:02:10 +02:00
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestConnect_Connected_InvalidArgs()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
2024-04-09 12:53:23 +02:00
|
|
|
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
|
2023-04-05 15:02:10 +02:00
|
|
|
|
|
|
|
var exception = Assert.Throws<AggregateException>(
|
|
|
|
() => { var lockIt = LockItEventBased.Authenticate(device, null, adapter, cipher).Result; },
|
|
|
|
"If connected no auth is requied.");
|
|
|
|
|
|
|
|
Assert.That(exception.InnerExceptions.Count > 0);
|
|
|
|
Assert.That(exception.InnerExceptions[0], Is.InstanceOf<BluetoothDisconnectedException>());
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestConnect_Connected()
|
|
|
|
{
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
2024-04-09 12:53:23 +02:00
|
|
|
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
|
2023-04-05 15:02:10 +02:00
|
|
|
var auth = Substitute.For<ICharacteristic>();
|
|
|
|
var lockControl = Substitute.For<IService>();
|
|
|
|
|
|
|
|
var authTdo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
Id = 12,
|
|
|
|
K_seed = new byte[] { (byte)'i', (byte)'V', (byte)'F', (byte)'m', (byte)'u', (byte)'T', (byte)'n', (byte)'K', (byte)'q', (byte)'E', (byte)'Y', (byte)'h', (byte)'m', (byte)'T', (byte)'l', (byte)'e' },
|
|
|
|
K_u = new byte[16]
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
device.State.Returns(Plugin.BLE.Abstractions.DeviceState.Connected);
|
|
|
|
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
|
|
|
|
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
|
2024-04-09 12:53:23 +02:00
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); // Write COPRI seed to lock
|
|
|
|
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS))); // Read lock seed
|
2023-04-05 15:02:10 +02:00
|
|
|
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
|
|
|
|
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
|
2024-04-09 12:53:23 +02:00
|
|
|
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); // Write COPRI seed to lock
|
2023-04-05 15:02:10 +02:00
|
|
|
|
|
|
|
device.Name.Returns("Origin");
|
|
|
|
|
2024-04-09 12:53:23 +02:00
|
|
|
Assert.That(
|
|
|
|
LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result.Name, Is.EqualTo("Origin"),
|
2023-04-05 15:02:10 +02:00
|
|
|
"If connected no auth is requied.");
|
|
|
|
}
|
|
|
|
|
|
|
|
[Test]
|
|
|
|
public void TestAuth()
|
|
|
|
{
|
|
|
|
var authTdo = new LockInfoAuthTdo.Builder
|
|
|
|
{
|
|
|
|
Id = 12,
|
|
|
|
K_seed = new byte[] { (byte)'c', (byte)'b', (byte)'z', (byte)'b', (byte)'y', (byte)'I', (byte)'q', (byte)'j', (byte)'v', (byte)'L', (byte)'V', (byte)'I', (byte)'t', (byte)'C', (byte)'B', (byte)'I' },
|
|
|
|
K_u = new byte[16]
|
|
|
|
}.Build();
|
|
|
|
|
|
|
|
var device = Substitute.For<IDevice>();
|
|
|
|
var adapter = Substitute.For<IAdapter>();
|
2024-04-09 12:53:23 +02:00
|
|
|
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
|
2023-04-05 15:02:10 +02:00
|
|
|
|
|
|
|
// Use factory to create LockIt-object.
|
|
|
|
var exception = Assert.Throws<AggregateException>(
|
|
|
|
() => { var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result; },
|
|
|
|
"If connected no auth is requied.");
|
|
|
|
|
|
|
|
Assert.That(exception.InnerExceptions.Count > 0);
|
|
|
|
Assert.That(exception.InnerExceptions[0], Is.InstanceOf<BluetoothDisconnectedException>());
|
|
|
|
}
|
2022-09-06 16:08:19 +02:00
|
|
|
}
|
2021-05-13 17:25:46 +02:00
|
|
|
}
|