Version 3.0.381

This commit is contained in:
Anja 2024-04-09 12:53:23 +02:00
parent f963c0a219
commit 3a363acf3a
1525 changed files with 60589 additions and 125098 deletions

View file

@ -0,0 +1,239 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions;
using Plugin.BLE.Abstractions.Contracts;
using ShareeBike.Services.BluetoothLock.BLE;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Services.BluetoothLock.Tdo;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Settings.BluetoothLock
{
[TestFixture]
public class TestLockIt
{
[Test]
public void TestAuthenticate_InvalidSeed()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var ciper = Substitute.For<ShareeBike.Model.Device.ICipher>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { 0 },
K_u = new byte[] { 1 }
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
Assert.That(() => LockItEventBased.Authenticate(device, authInfo, adapter, ciper), Throws.InstanceOf<AuthKeyException>());
}
[Test]
public void TestAuthenticate_InvalidAuthKey()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var ciper = Substitute.For<ShareeBike.Model.Device.ICipher>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { (byte)'t', (byte)'q', (byte)'2', (byte)'n', (byte)'c', (byte)'A', (byte)'I', (byte)'v', (byte)'M', (byte)'t', (byte)'h', (byte)'g', (byte)'x', (byte)'a', (byte)'z', (byte)'B' },
K_u = new byte[] { }
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
Assert.That(async () => { await LockItEventBased.Authenticate(device, authInfo, adapter, ciper); }, Throws.InstanceOf<AuthKeyException>());
}
[Test]
public void TestAuthenticate_Invalidated()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var state = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { (byte)'z', (byte)'D', (byte)'G', (byte)'x', (byte)'q', (byte)'M', (byte)'f', (byte)'A', (byte)'F', (byte)'q', (byte)'g', (byte)'N', (byte)'V', (byte)'r', (byte)'N', (byte)'Y' },
K_u = new byte[] { 1 }
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
// Call authenticate to invalidate seed
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
// Authenticate again to
var execption = Assert.Throws<AggregateException>(() => { var dummy = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result; });
Assert.That(
execption.InnerExceptions[0].Message,
Does.Contain("Seed 122,68,71,120,113,77,102,65,70,113,103,78,86,114,78,89 was already used."));
}
[Test]
public void TestAuthenticate_GetAuthCharacteristicThrowsException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var state = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
K_u = new byte[] { 1 }
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult((ICharacteristic)null));
// Authenticate again to
Assert.That(() => LockItEventBased.Authenticate(device, authInfo, adapter, cipher), Throws.InstanceOf<CoundntGetCharacteristicException>());
}
[Test]
public async Task TestAuthenticate_GetLockState_Closed()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var state = Substitute.For<ICharacteristic>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 },
K_u = new byte[] { 1 }
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
// Calls related to get lock state.
// Call authenticate to invalidate seed
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(state));
state.ReadAsync(Arg.Any<CancellationToken>()).Returns((new byte[] { 1 }, LockItBase.ERRORCODE_SUCCESS));
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
Assert.That((await lockIt.GetLockStateAsync()).State, Is.EqualTo(LockitLockingState.Closed));
}
[Test]
public async Task TestAuthenticate_GetLockState_UndefinedState()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var state = Substitute.For<ICharacteristic>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 },
K_u = new byte[] { 1 }
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
// Calls related to get lock state.
// Call authenticate to invalidate seed
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(state));
state.ReadAsync(Arg.Any<CancellationToken>()).Returns((new byte[] { 99 }, LockItBase.ERRORCODE_SUCCESS)); // This value should never be returned from ILockit.
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
Assert.That((await lockIt.GetLockStateAsync()).State, Is.Null);
}
[Test]
public void TestAuthenticate_GetLockState_GetStateCharacteristicThrowsException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authInfo = new LockInfoAuthTdo.Builder
{
K_seed = new byte[] { (byte)'y', (byte)'D', (byte)'G', (byte)'x', (byte)'q', (byte)'M', (byte)'f', (byte)'A', (byte)'F', (byte)'q', (byte)'g', (byte)'N', (byte)'V', (byte)'r', (byte)'N', (byte)'Y' },
K_u = new byte[] { 1 }
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns((Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS))));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("00000000-0000-0000-0000-000000000001"));
// Calls related to get lock state.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult((ICharacteristic)null));
var lockIt = LockItEventBased.Authenticate(device, authInfo, adapter, cipher).Result;
Assert.That(async () => (await lockIt.GetLockStateAsync()).State, Throws.InstanceOf<CoundntGetCharacteristicException>());
}
}
}

View file

@ -0,0 +1,188 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions;
using Plugin.BLE.Abstractions.Contracts;
using ShareeBike.Model.Device;
using ShareeBike.Services.BluetoothLock.BLE;
using ShareeBike.Services.BluetoothLock.Tdo;
namespace LockIt.BLE.Tests.Services.BluetoothLock.BLE
{
public class TestLockItBase
{
[Test]
public void TestName_Null()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'X', (byte)'D', (byte)'G', (byte)'x', (byte)'q', (byte)'M', (byte)'f', (byte)'A', (byte)'F', (byte)'q', (byte)'g', (byte)'N', (byte)'V', (byte)'r', (byte)'N', (byte)'Y' },
K_u = new byte[16]
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns((string)null);
// Use factory to create LockIt-object.
var lockIt = LockItBaseTest.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.Name, Is.EqualTo(string.Empty));
}
[Test]
public void TestName()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'m', (byte)'x', (byte)'p', (byte)'J', (byte)'g', (byte)'D', (byte)'D', (byte)'i', (byte)'o', (byte)'T', (byte)'F', (byte)'M', (byte)'S', (byte)'E', (byte)'m', (byte)'E' },
K_u = new byte[16]
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Use factory to create LockIt-object.
var lockIt = LockItBaseTest.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.Name, Is.EqualTo("ISHAREIT+123"));
}
[Test]
public void TestId()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'l', (byte)'x', (byte)'p', (byte)'J', (byte)'g', (byte)'D', (byte)'D', (byte)'i', (byte)'o', (byte)'T', (byte)'F', (byte)'M', (byte)'S', (byte)'E', (byte)'m', (byte)'E' },
K_u = new byte[16]
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Use factory to create LockIt-object.
var lockIt = LockItBaseTest.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.Id, Is.EqualTo(123));
}
[Test]
public void TestGuid()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'l', (byte)'x', (byte)'p', (byte)'J', (byte)'g', (byte)'D', (byte)'D', (byte)'i', (byte)'o', (byte)'T', (byte)'F', (byte)'M', (byte)'S', (byte)'E', (byte)'m', (byte)'E' },
K_u = new byte[16]
}.Build();
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(Arg.Any<Guid>()).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Use factory to create LockIt-object.
var lockIt = LockItBaseTest.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.Guid, Is.EqualTo(new Guid("72bdc44f-c588-44f3-b6df-9aace7daafdd")));
}
/// <summary> Derives from LockItBase class for testing purposes. </summary>
private class LockItBaseTest : LockItBase
{
private LockItBaseTest(IDevice device, IAdapter adapter, ICipher cipher) : base(device, adapter, cipher)
{
}
/// <summary> Connects to device. </summary>
/// <param name="authInfo">Info required to connect.</param>
/// <param name="device">Device with must be connected.</param>
/// <returns>True if connecting succeeded, false if not.</returns>
public static async Task<LockItBase> Authenticate(
IDevice device,
LockInfoAuthTdo authInfo,
IAdapter adapter,
ICipher cipher)
=> await Authenticate(
device,
authInfo,
adapter,
cipher,
() => new LockItBaseTest(device, adapter, cipher));
public override Task<LockitLockingState?> CloseAsync()
{
throw new NotImplementedException();
}
public override Task<LockitLockingState?> OpenAsync()
{
throw new NotImplementedException();
}
public override Task ReconnectAsync(LockInfoAuthTdo authInfo, TimeSpan connectTimeout)
{
throw new NotImplementedException();
}
}
}
}

View file

@ -0,0 +1,315 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
using Plugin.BLE.Abstractions.EventArgs;
using ShareeBike.Services.BluetoothLock.BLE;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Services.BluetoothLock.Tdo;
using DeviceState = Plugin.BLE.Abstractions.DeviceState;
namespace LockIt.BLE.Tests
{
public class TestLockItEventBased
{
[Test]
public void TestOpen()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var activateCharacteristic = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'p', (byte)'a', (byte)'w', (byte)'m', (byte)'X', (byte)'8', (byte)'T', (byte)'X', (byte)'Q', (byte)'Z', (byte)'d', (byte)'l', (byte)'k', (byte)'3', (byte)'e', (byte)'V', },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* State read before open action: closed */ }, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateCharacteristic));
activateCharacteristic.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Open /* State passed as event argument after opening. */});
// Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
var lockState = lockIt.OpenAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
Assert.That(lockState.Result, Is.EqualTo(LockitLockingState.Open));
}
[Test]
public void TestOpen_ThrowsCouldntOpenInconsistentStateExecption()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'m', (byte)'l', (byte)'Q', (byte)'I', (byte)'S', (byte)'z', (byte)'p', (byte)'H', (byte)'m', (byte)'n', (byte)'V', (byte)'n', (byte)'7', (byte)'f', (byte)'i', (byte)'3' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* State read before open action: closed */ }, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Closed /* State passed as event argument after opening. */});
// Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(async () =>
{
var lockState = lockIt.OpenAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
await lockState;
},
Throws.InstanceOf<CouldntOpenInconsistentStateExecption>());
}
[Test]
public void TestOpen_ThrowsCouldntOpenBoltBlockedException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'i', (byte)'r', (byte)'F', (byte)'h', (byte)'G', (byte)'T', (byte)'z', (byte)'P', (byte)'F', (byte)'Z', (byte)'n', (byte)'z', (byte)'Y', (byte)'B', (byte)'s', (byte)'9' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* closed */}, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 4 /* bold blocked */ }, LockItBase.ERRORCODE_SUCCESS)));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.CouldntOpenBoltBlocked /* State passed as event argument after opening. */});
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
// Use factory to create LockIt-object.
Assert.That(async () =>
{
var lockState = lockIt.OpenAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
await lockState;
},
Throws.InstanceOf<CouldntOpenBoldIsBlockedException>());
}
[Test]
public void TestClose()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'I', (byte)'7', (byte)'y', (byte)'B', (byte)'f', (byte)'s', (byte)'v', (byte)'L', (byte)'G', (byte)'L', (byte)'7', (byte)'b', (byte)'7', (byte)'X', (byte)'z', (byte)'t' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to close functionality.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* open */ }, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 1 /* closed */}, LockItBase.ERRORCODE_SUCCESS)));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Closed /* State passed as event argument after closing. */});
// Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
var lockState = lockIt.CloseAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
Assert.That(lockState.Result, Is.EqualTo(LockitLockingState.Closed));
}
[Test]
public void TestClose_ThrowsCouldntCloseInconsistentStateExecption()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'8', (byte)'q', (byte)'3', (byte)'9', (byte)'i', (byte)'6', (byte)'c', (byte)'g', (byte)'9', (byte)'L', (byte)'V', (byte)'7', (byte)'T', (byte)'G', (byte)'l', (byte)'f' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to close functionality.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* opened */}, LockItBase.ERRORCODE_SUCCESS)));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.Unknown /* State passed as event argument after closing. */}); /* changed from .Open to .Unknown (20.02.23, AMM) after bug fix #657. */
// Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
// Use factory to create LockIt-object.
Assert.That(async () =>
{
var lockState = lockIt.CloseAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
await lockState;
},
Throws.InstanceOf<CouldntCloseInconsistentStateExecption>());
}
[Test]
public void TestClose_ThrowsCouldntCloseBoltBlockedException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var lockControl = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var stateCharacteristic = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'v', (byte)'f', (byte)'u', (byte)'v', (byte)'j', (byte)'E', (byte)'b', (byte)'x', (byte)'p', (byte)'z', (byte)'a', (byte)'h', (byte)'V', (byte)'5', (byte)'9', (byte)'i' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(lockControl));
lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to Close functionality.
lockControl.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* open */ }, LockItBase.ERRORCODE_SUCCESS)));
lockControl.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
stateCharacteristic.Value.Returns(new byte[] { (byte)LockitLockingState.CouldntCloseBoltBlocked /* State passed as event argument after opening. */});
// Use factory to create LockIt-object.
var lockIt = LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result;
// Use factory to create LockIt-object.
Assert.That(async () =>
{
var lockState = lockIt.CloseAsync();
controlCharacteristic.ValueUpdated += Raise.EventWith(new object(), new CharacteristicUpdatedEventArgs(stateCharacteristic));
await lockState;
},
Throws.InstanceOf<CouldntCloseBoltBlockedException>());
}
}
}

View file

@ -0,0 +1,315 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock.BLE;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Services.BluetoothLock.Tdo;
using DeviceState = Plugin.BLE.Abstractions.DeviceState;
namespace LockIt.BLE.Tests.Services.BluetoothLock.BLE
{
public class TestLockItPolling
{
[Test]
public void TestOpen()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'o', (byte)'a', (byte)'w', (byte)'m', (byte)'X', (byte)'8', (byte)'T', (byte)'X', (byte)'Q', (byte)'Z', (byte)'d', (byte)'l', (byte)'k', (byte)'3', (byte)'e', (byte)'V', },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* state read after sending open commant: closed */ }, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 0 /* state read after sending open commant: open */}, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.OpenAsync().Result, Is.EqualTo(LockitLockingState.Open));
}
[Test]
public void TestOpen_ThrowsCouldntOpenInconsistentStateExecption()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'n', (byte)'l', (byte)'Q', (byte)'I', (byte)'S', (byte)'z', (byte)'p', (byte)'H', (byte)'m', (byte)'n', (byte)'V', (byte)'n', (byte)'7', (byte)'f', (byte)'i', (byte)'3' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* closed */}, LockItBase.ERRORCODE_SUCCESS))); // Closed is returned twice => Inconsistent state ....
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(async () => { var result = await lockIt.OpenAsync(); }, Throws.InstanceOf<CouldntOpenInconsistentStateExecption>());
}
[Test]
public void TestOpen_ThrowsCouldntOpenBoltBlockedException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'h', (byte)'r', (byte)'F', (byte)'h', (byte)'G', (byte)'T', (byte)'z', (byte)'P', (byte)'F', (byte)'Z', (byte)'n', (byte)'z', (byte)'Y', (byte)'B', (byte)'s', (byte)'9' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to open functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 1 /* closed */}, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 4 /* bold blocked */ }, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(async () => { var result = await lockIt.OpenAsync(); }, Throws.InstanceOf<CouldntOpenBoldIsBlockedException>());
}
[Test]
public void TestClose()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'H', (byte)'7', (byte)'y', (byte)'B', (byte)'f', (byte)'s', (byte)'v', (byte)'L', (byte)'G', (byte)'L', (byte)'7', (byte)'b', (byte)'7', (byte)'X', (byte)'z', (byte)'t' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to close functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* open */ }, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 1 /* closed */}, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(lockIt.CloseAsync().Result, Is.EqualTo(LockitLockingState.Closed));
}
[Test]
public void TestClose_ThrowsCouldntCloseInconsistentStateExecption()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'7', (byte)'q', (byte)'3', (byte)'9', (byte)'i', (byte)'6', (byte)'c', (byte)'g', (byte)'9', (byte)'L', (byte)'V', (byte)'7', (byte)'T', (byte)'G', (byte)'l', (byte)'f' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to close functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* opened */}, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(async () => { var result = await lockIt.CloseAsync(); }, Throws.InstanceOf<CouldntCloseInconsistentStateExecption>());
}
[Test]
public async Task TestClose_ThrowsCouldntCloseInconsistentStateExecptionUnknownState()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'7', (byte)'q', (byte)'3', (byte)'9', (byte)'i', (byte)'6', (byte)'c', (byte)'g', (byte)'9', (byte)'L', (byte)'V', (byte)'7', (byte)'T', (byte)'G', (byte)'l', (byte)'g' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to close functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 99 /* lock should never return this exception */}, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(
(await lockIt.CloseAsync()),
Is.Null);
}
[Test]
public void TestClose_ThrowsCouldntCloseBoltBlockedException()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
var auth = Substitute.For<ICharacteristic>();
var controlService = Substitute.For<IService>();
var controlCharacteristic = Substitute.For<ICharacteristic>();
var activateLock = Substitute.For<ICharacteristic>();
var authTdo = new LockInfoAuthTdo.Builder
{
Id = 12,
K_seed = new byte[] { (byte)'u', (byte)'f', (byte)'u', (byte)'v', (byte)'j', (byte)'E', (byte)'b', (byte)'x', (byte)'p', (byte)'z', (byte)'a', (byte)'h', (byte)'V', (byte)'5', (byte)'9', (byte)'i' },
K_u = new byte[16]
}.Build();
// Calls related to Authenticate functionality.
device.State.Returns(DeviceState.Connected);
device.Id.Returns(new Guid("0000f00d-1212-efde-1523-785fef13d123"));
device.GetServiceAsync(Arg.Any<Guid>(), Arg.Any<CancellationToken>()).Returns(Task.FromResult(controlService));
controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth));
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
auth.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)));
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(LockItBase.ERRORCODE_SUCCESS);
device.Name.Returns("ISHAREIT+123");
// Calls related to Close functionality.
controlService.GetCharacteristicAsync(new Guid("0000baaa-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(controlCharacteristic));
controlCharacteristic.ReadAsync(Arg.Any<CancellationToken>()).Returns(Task.FromResult((new byte[] { 0 /* open */}, LockItBase.ERRORCODE_SUCCESS)), Task.FromResult((new byte[] { 5 /* bold blocked */ }, LockItBase.ERRORCODE_SUCCESS)));
controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock));
activateLock.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS));
// Use factory to create LockIt-object.
var lockIt = LockItPolling.Authenticate(device, authTdo, adapter, cipher).Result;
Assert.That(async () => { var result = await lockIt.CloseAsync(); }, Throws.InstanceOf<CouldntCloseBoltBlockedException>());
}
}
}

View file

@ -0,0 +1,142 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using Plugin.BLE.Abstractions.Contracts;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.BLE;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Services.BluetoothLock.Tdo;
namespace LockIt.BLE.Tests.Services.BluetoothLock.BLE
{
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>();
await LockItServiceBase.CheckReconnect(
devices,
locksInfo,
TimeSpan.FromSeconds(0));
await disconnectedDevice.DidNotReceive().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
}
[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"));
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() };
await LockItServiceBase.CheckReconnect(
devices,
locksInfo,
TimeSpan.FromSeconds(0));
await disconnectedDevice.DidNotReceive().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
}
[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"));
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() };
await LockItServiceBase.CheckReconnect(
devices,
locksInfo,
TimeSpan.FromSeconds(0));
await disconnectedDevice.Received().ReconnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
}
[Test]
public void TestConnect_Connected_InvalidArgs()
{
var device = Substitute.For<IDevice>();
var adapter = Substitute.For<IAdapter>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
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>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
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));
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
cipher.Decrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[3]);
cipher.Encrypt(Arg.Any<byte[]>(), Arg.Any<byte[]>()).Returns(new byte[16]);
auth.WriteAsync(Arg.Any<byte[]>()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); // Write COPRI seed to lock
device.Name.Returns("Origin");
Assert.That(
LockItEventBased.Authenticate(device, authTdo, adapter, cipher).Result.Name, Is.EqualTo("Origin"),
"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>();
var cipher = Substitute.For<ShareeBike.Model.Device.ICipher>();
// 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>());
}
}
}

View file

@ -0,0 +1,43 @@
using System;
using NUnit.Framework;
using ShareeBike.Services.BluetoothLock.BLE;
namespace LockIt.BLE.Tests.Services.BluetoothLock.BLE
{
[TestFixture]
public class TestPluginBleHelper
{
[Test]
public void TestGetDeviceState()
{
foreach (Plugin.BLE.Abstractions.DeviceState state in Enum.GetValues(typeof(Plugin.BLE.Abstractions.DeviceState)))
{
switch (state)
{
case Plugin.BLE.Abstractions.DeviceState.Connecting:
Assert.That(state.GetDeviceState(),
Is.EqualTo(ShareeBike.Services.BluetoothLock.DeviceState.Connecting));
break;
case Plugin.BLE.Abstractions.DeviceState.Connected:
Assert.That(state.GetDeviceState(),
Is.EqualTo(ShareeBike.Services.BluetoothLock.DeviceState.Connected));
break;
case Plugin.BLE.Abstractions.DeviceState.Disconnected:
Assert.That(state.GetDeviceState(),
Is.EqualTo(ShareeBike.Services.BluetoothLock.DeviceState.Disconnected));
break;
case Plugin.BLE.Abstractions.DeviceState.Limited:
Assert.That(state.GetDeviceState(),
Is.EqualTo(ShareeBike.Services.BluetoothLock.DeviceState.Limited));
break;
default:
throw new Exception($"Unexpected state {state} detected.");
}
}
}
}
}