2023-08-31 12:20:06 +02:00
using System ;
using System.Threading ;
using System.Threading.Tasks ;
using NSubstitute ;
using NSubstitute.ExceptionExtensions ;
using NUnit.Framework ;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock ;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command ;
using TINK.Model.Connector ;
using TINK.Model.Device ;
using TINK.Model.State ;
using TINK.Model.User ;
2023-08-31 12:31:38 +02:00
using TINK.Repository.Request ;
2023-08-31 12:20:06 +02:00
using TINK.Services.BluetoothLock ;
using TINK.Services.Geolocation ;
using static TINK . Model . Bikes . BikeInfoNS . BluetoothLock . Command . GetLockedLocationCommand ;
namespace TestShareeLib.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
public class TestGetBikeLocationCommand
{
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks> Replaces test TestReturnOutOfReach which was removed for sharee.bike version ~3.0.362. </remarks>
[Test]
public void TestReturnLastGeolocatonNullLockOutOfReach ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var listener = Substitute . For < IGetLockedLocationCommandListener > ( ) ;
bike . Id . Returns ( "0" ) ;
bike . LockInfo . Location . Returns ( ( IGeolocation ) null ) ; // When locking bike geolocation was not available.
locks [ 0 ] . GetDeviceState ( ) . Returns ( DeviceState . Disconnected ) ; // Simulate bike out of reach.
locks . DisconnectAsync ( 0 , Arg . Any < Guid > ( ) ) . Returns ( LockingState . UnknownDisconnected ) ; // Simulate disconnecting.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
Assert . That (
async ( ) = > await InvokeAsync < TestGetBikeLocationCommand > (
bike ,
geolocation ,
locks ,
listener : listener ) ,
Throws . TypeOf < Exception > ( ) ) ;
// Verify behavior
Received . InOrder ( ( ) = >
{
listener . ReportStep ( Step . StartingQueryLocation ) ;
var location = bike . LockInfo . Location ;
locks [ 0 ] . GetDeviceState ( ) ;
listener . ReportStateAsync ( State . DisconnetedNoLocationError , "" ) ;
listener . ReportStep ( Step . DisconnectingLockOnDisconnectedNoLocationError ) ;
locks . DisconnectAsync ( 0 , Arg . Any < Guid > ( ) ) ;
listener . ReportStateAsync ( State . QueryLocationSucceeded , "" ) ;
} ) ;
Assert . That (
bike . LockInfo . State ,
Is . EqualTo ( LockingState . UnknownDisconnected ) ) ;
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks>Replaces test TestReturnLockInReachNoGeolocation which was removed for sharee.bike older ~ 3.0.362.</remarks>
[Test]
public void TestReturnStartGetGeolocationException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var listener = Substitute . For < IGetLockedLocationCommandListener > ( ) ;
bike . Id . Returns ( "0" ) ;
bike . LockInfo . Location . Returns ( ( IGeolocation ) null ) ; // When locking bike geolocation was not available.
locks [ 0 ] . GetDeviceState ( ) . Returns ( DeviceState . Connected ) ; // Simulate bike in reach.
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime ? > ( ) ) . Throws ( new Exception ( "Ups..." ) ) ; // Simulate error when starting query for geolocation.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state does not change.
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Locking state does not change.
var subsequent = InvokeAsync < TestGetBikeLocationCommand > (
bike ,
geolocation ,
locks ,
listener : listener ) ;
// Verify behavior
Received . InOrder ( async ( ) = >
{
listener . ReportStep ( Step . StartingQueryLocation ) ;
locks [ 0 ] . GetDeviceState ( ) ;
await geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime ? > ( ) ) ;
await listener . ReportStateAsync ( State . QueryLocationFailed , "Ups..." ) ;
} ) ;
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
[Test]
public void TestReturnGetGeolocationException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var listener = Substitute . For < IGetLockedLocationCommandListener > ( ) ;
bike . Id . Returns ( "0" ) ;
bike . LockInfo . Location . Returns ( ( IGeolocation ) null ) ; // When locking bike geolocation was not available.
locks [ 0 ] . GetDeviceState ( ) . Returns ( DeviceState . Connected ) ; // Simulate bike in reach.
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime ? > ( ) )
. Returns ( Task . FromException < IGeolocation > ( new Exception ( "Ups..." ) ) ) ; // Simulate error starting query for geolocation.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state does not change.
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Locking state does not change.
Assert . That (
async ( ) = > await InvokeAsync < TestGetBikeLocationCommand > (
bike ,
geolocation ,
locks ,
listener : listener ) ,
Throws . TypeOf < Exception > ( ) ) ;
// Verify behavior
Received . InOrder ( async ( ) = >
{
listener . ReportStep ( Step . StartingQueryLocation ) ;
locks [ 0 ] . GetDeviceState ( ) ;
await geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime ? > ( ) ) ;
await listener . ReportStateAsync ( State . QueryLocationFailed , "Ups..." ) ;
} ) ;
}
/// <summary>
/// Use case: End rental.
/// Final state: Disposable closed
/// </summary>
[Test]
public async Task TestReturnLockInReach ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var listener = Substitute . For < IGetLockedLocationCommandListener > ( ) ;
bike . LockInfo . Location . Returns ( ( IGeolocation ) null ) ;
bike . Id . Returns ( "0" ) ;
locks [ 0 ] . GetDeviceState ( ) . Returns ( DeviceState . Connected ) ; // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
var location = Substitute . For < IGeolocation > ( ) ;
location . Latitude . Returns ( 7 ) ;
location . Longitude . Returns ( 9 ) ;
location . Timestamp . Returns ( DateTimeOffset . MinValue ) ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) . Returns ( Task . FromResult (
location
) ) ; ;
var lockingLocation = await InvokeAsync < TestGetBikeLocationCommand > (
bike ,
geolocation ,
locks ,
( ) = > DateTime . MinValue ,
listener ) ;
Assert . That ( lockingLocation . Latitude , Is . EqualTo ( 7 ) ) ;
Assert . That ( lockingLocation . Longitude , Is . EqualTo ( 9 ) ) ;
// Verify behavior
Received . InOrder ( async ( ) = >
{
listener . ReportStep ( Step . StartingQueryLocation ) ;
var dummyLoc = bike . LockInfo . Location ; // Check if location was available when closing lock.
locks [ 0 ] . GetDeviceState ( ) ; // Check if bike is connected.
await geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ; // Query current location.
await listener . ReportStateAsync ( State . QueryLocationSucceeded , string . Empty ) ;
} ) ;
}
2023-08-31 12:31:38 +02:00
/// <summary>
/// Use case: End rental.
/// Final state: Disposable closed
/// </summary>
[Test]
public async Task TestReturnClosingLockLocationAvailable ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var listener = Substitute . For < IGetLockedLocationCommandListener > ( ) ;
var closingLockLocation = Substitute . For < IGeolocation > ( ) ;
closingLockLocation . Latitude . Returns ( 7 ) ;
closingLockLocation . Longitude . Returns ( 9 ) ;
closingLockLocation . Timestamp . Returns ( DateTimeOffset . MinValue ) ;
bike . LockInfo . Location . Returns ( ( IGeolocation ) closingLockLocation ) ; // When locking bike geolocation was available.
var lockingLocation = await InvokeAsync < TestGetBikeLocationCommand > (
bike ,
geolocation ,
locks ,
( ) = > DateTime . MinValue ,
listener ) ;
// Verify behavior
Received . InOrder ( ( ) = >
{
listener . ReportStep ( Step . StartingQueryLocation ) ;
return ;
} ) ;
}
2023-08-31 12:20:06 +02:00
}
}