using NSubstitute; using NUnit.Framework; using Plugin.BLE.Abstractions.Contracts; using System; using System.Threading.Tasks; using TINK.Services.BluetoothLock.Tdo; using TINK.Services.BluetoothLock.Exception; using TINK.Services.BluetoothLock.BLE; using DeviceState = Plugin.BLE.Abstractions.DeviceState; using System.Threading; namespace TestLockItBLE.Services.BluetoothLock.BLE { public class TestLockItPolling { [Test] public void TestOpen() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 1 /* state read after sending open commant: closed */ }), Task.FromResult(new byte[] { 0 /* state read after sending open commant: open */})); controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 1 /* closed */})); // Closed is returned twice => Inconsistent state .... controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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()); } [Test] public void TestOpen_ThrowsCouldntOpenBoldBlockedException() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 1 /* closed */}), Task.FromResult(new byte[] { 4 /* bold blocked */ })); controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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()); } [Test] public void TestClose() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 0 /* open */ }), Task.FromResult(new byte[] { 1 /* closed */})); controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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_ThrowsCouldntOpenInconsistentStateExecption() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 0 /* opened */})); controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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()); } [Test] public void TestClose_ThrowsCouldntOpenBoldBlockedException() { var device = Substitute.For(); var adapter = Substitute.For(); var cipher = Substitute.For(); var auth = Substitute.For(); var controlService = Substitute.For(); var controlCharacteristic = Substitute.For(); var activateLock = Substitute.For(); 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(), Arg.Any()).Returns(Task.FromResult(controlService)); controlService.GetCharacteristicAsync(new Guid("0000baab-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(auth)); auth.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); auth.ReadAsync(Arg.Any()).Returns(Task.FromResult(new byte[8])); 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(true); 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()).Returns(Task.FromResult(new byte[] { 0 /* open */}), Task.FromResult(new byte[] { 5 /* bold blocked */ })); controlService.GetCharacteristicAsync(new Guid("0000beee-1212-efde-1523-785fef13d123")).Returns(Task.FromResult(activateLock)); activateLock.WriteAsync(Arg.Any()).Returns(Task.FromResult(true)); // 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()); } } }