sharee.bike-App/LockIt.BLE.Tests/Services/BluetoothLock/BLE/TestLockIt.cs
2024-04-09 12:53:23 +02:00

240 lines
11 KiB
C#

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>());
}
}
}