2023-08-31 12:20:06 +02:00
using System ;
2022-08-30 15:42:25 +02:00
using System.Threading ;
using System.Threading.Tasks ;
using NSubstitute ;
2021-07-12 21:31:46 +02:00
using NUnit.Framework ;
using Plugin.BLE.Abstractions ;
using Plugin.BLE.Abstractions.Contracts ;
2024-04-09 12:53:23 +02:00
using ShareeBike.Services.BluetoothLock.BLE ;
using ShareeBike.Services.BluetoothLock.Exception ;
using ShareeBike.Services.BluetoothLock.Tdo ;
2021-07-12 21:31:46 +02:00
2024-04-09 12:53:23 +02:00
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Settings.BluetoothLock
2021-07-12 21:31:46 +02:00
{
2022-09-06 16:08:19 +02:00
[TestFixture]
public class TestLockIt
{
[Test]
public void TestAuthenticate_InvalidSeed ( )
{
var device = Substitute . For < IDevice > ( ) ;
var adapter = Substitute . For < IAdapter > ( ) ;
2024-04-09 12:53:23 +02:00
var ciper = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 > ( ) ;
2024-04-09 12:53:23 +02:00
var ciper = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 > ( ) ;
2024-04-09 12:53:23 +02:00
var cipher = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
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 ) ) ) ;
2022-09-06 16:08:19 +02:00
cipher . Decrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 3 ] ) ;
cipher . Encrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 16 ] ) ;
2024-04-09 12:53:23 +02:00
auth . WriteAsync ( Arg . Any < byte [ ] > ( ) ) . Returns ( LockItBase . ERRORCODE_SUCCESS ) ;
2022-09-06 16:08:19 +02:00
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 > ( ) ;
2024-04-09 12:53:23 +02:00
var cipher = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 > ( ) ;
2024-04-09 12:53:23 +02:00
var cipher = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
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 ) ) ) ;
2022-09-06 16:08:19 +02:00
cipher . Decrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 3 ] ) ;
cipher . Encrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 16 ] ) ;
2024-04-09 12:53:23 +02:00
auth . WriteAsync ( Arg . Any < byte [ ] > ( ) ) . Returns ( LockItBase . ERRORCODE_SUCCESS ) ;
2022-09-06 16:08:19 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
state . ReadAsync ( Arg . Any < CancellationToken > ( ) ) . Returns ( ( new byte [ ] { 1 } , LockItBase . ERRORCODE_SUCCESS ) ) ;
2022-09-06 16:08:19 +02:00
var lockIt = LockItEventBased . Authenticate ( device , authInfo , adapter , cipher ) . Result ;
Assert . That ( ( await lockIt . GetLockStateAsync ( ) ) . State , Is . EqualTo ( LockitLockingState . Closed ) ) ;
}
2023-08-31 12:20:06 +02:00
[Test]
public async Task TestAuthenticate_GetLockState_UndefinedState ( )
{
var device = Substitute . For < IDevice > ( ) ;
var adapter = Substitute . For < IAdapter > ( ) ;
2024-04-09 12:53:23 +02:00
var cipher = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2023-08-31 12:20:06 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
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 ) ) ) ;
2023-08-31 12:20:06 +02:00
cipher . Decrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 3 ] ) ;
cipher . Encrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 16 ] ) ;
2024-04-09 12:53:23 +02:00
auth . WriteAsync ( Arg . Any < byte [ ] > ( ) ) . Returns ( LockItBase . ERRORCODE_SUCCESS ) ;
2023-08-31 12:20:06 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
state . ReadAsync ( Arg . Any < CancellationToken > ( ) ) . Returns ( ( new byte [ ] { 99 } , LockItBase . ERRORCODE_SUCCESS ) ) ; // This value should never be returned from ILockit.
2023-08-31 12:20:06 +02:00
var lockIt = LockItEventBased . Authenticate ( device , authInfo , adapter , cipher ) . Result ;
Assert . That ( ( await lockIt . GetLockStateAsync ( ) ) . State , Is . Null ) ;
}
2022-09-06 16:08:19 +02:00
[Test]
public void TestAuthenticate_GetLockState_GetStateCharacteristicThrowsException ( )
{
var device = Substitute . For < IDevice > ( ) ;
var adapter = Substitute . For < IAdapter > ( ) ;
2024-04-09 12:53:23 +02:00
var cipher = Substitute . For < ShareeBike . Model . Device . ICipher > ( ) ;
2022-09-06 16:08:19 +02:00
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 ) ) ;
2024-04-09 12:53:23 +02:00
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 ) ) ) ) ;
2022-09-06 16:08:19 +02:00
cipher . Decrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 3 ] ) ;
cipher . Encrypt ( Arg . Any < byte [ ] > ( ) , Arg . Any < byte [ ] > ( ) ) . Returns ( new byte [ 16 ] ) ;
2024-04-09 12:53:23 +02:00
auth . WriteAsync ( Arg . Any < byte [ ] > ( ) ) . Returns ( LockItBase . ERRORCODE_SUCCESS ) ;
2022-09-06 16:08:19 +02:00
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 > ( ) ) ;
}
}
2021-07-12 21:31:46 +02:00
}