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(); var adapter = Substitute.For(); var ciper = Substitute.For(); 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()); } [Test] public void TestAuthenticate_InvalidAuthKey() { var device = Substitute.For(); var adapter = Substitute.For(); var ciper = Substitute.For(); 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()); } [Test] public void TestAuthenticate_Invalidated() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var lockControl = Substitute.For(); var state = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(lockControl)); lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS))); cipher.Decrypt(Arg.Any(), Arg.Any()).Returns(new byte[3]); cipher.Encrypt(Arg.Any(), Arg.Any()).Returns(new byte[16]); auth.WriteAsync(Arg.Any()).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(() => { 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(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var lockControl = Substitute.For(); var state = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).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()); } [Test] public async Task TestAuthenticate_GetLockState_Closed() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var lockControl = Substitute.For(); var state = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(lockControl)); lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS))); cipher.Decrypt(Arg.Any(), Arg.Any()).Returns(new byte[3]); cipher.Encrypt(Arg.Any(), Arg.Any()).Returns(new byte[16]); auth.WriteAsync(Arg.Any()).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()).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(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var lockControl = Substitute.For(); var state = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(lockControl)); lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS))); cipher.Decrypt(Arg.Any(), Arg.Any()).Returns(new byte[3]); cipher.Encrypt(Arg.Any(), Arg.Any()).Returns(new byte[16]); auth.WriteAsync(Arg.Any()).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()).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(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var lockControl = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(lockControl)); lockControl.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(LockItBase.ERRORCODE_SUCCESS)); auth.ReadAsync(Arg.Any()).Returns((Task.FromResult((new byte[8], LockItBase.ERRORCODE_SUCCESS)))); cipher.Decrypt(Arg.Any(), Arg.Any()).Returns(new byte[3]); cipher.Encrypt(Arg.Any(), Arg.Any()).Returns(new byte[16]); auth.WriteAsync(Arg.Any()).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()); } } }