2022-09-06 16:08:19 +02:00
using System ;
2021-05-13 20:09:46 +02:00
using System.Threading.Tasks ;
2022-08-30 15:42:25 +02:00
using Newtonsoft.Json ;
using NSubstitute ;
using NUnit.Framework ;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock ;
2023-08-31 12:20:06 +02:00
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command ;
2021-05-13 20:09:46 +02:00
using TINK.Model.Connector ;
2022-08-30 15:42:25 +02:00
using TINK.Model.Device ;
using TINK.Model.State ;
using TINK.Model.User ;
2021-06-26 20:57:55 +02:00
using TINK.Repository.Exception ;
2022-08-30 15:42:25 +02:00
using TINK.Repository.Request ;
using TINK.Repository.Response ;
2021-05-13 20:09:46 +02:00
using TINK.Services.BluetoothLock ;
using TINK.Services.BluetoothLock.Exception ;
using TINK.Services.BluetoothLock.Tdo ;
2022-04-10 17:38:34 +02:00
using TINK.Services.Geolocation ;
2021-05-13 20:09:46 +02:00
using TINK.View ;
using TINK.ViewModel ;
using TINK.ViewModel.Bikes ;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler ;
2023-08-31 12:20:06 +02:00
using static TINK . Model . Bikes . BikeInfoNS . BluetoothLock . Command . CloseCommand ;
2021-05-13 20:09:46 +02:00
namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
2023-08-31 12:20:06 +02:00
[TestFixture]
2022-09-06 16:08:19 +02:00
public class TestReservedUnknown
{
2023-08-31 12:20:06 +02:00
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor ( )
2022-09-06 16:08:19 +02:00
{
2023-08-31 12:20:06 +02:00
var handler = new ReservedUnknown (
Substitute . For < IBikeInfoMutable > ( ) ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > Substitute . For < IConnector > ( ) ,
Substitute . For < IGeolocationService > ( ) ,
Substitute . For < ILocksService > ( ) ,
( ) = > Substitute . For < IPollingUpdateTaskManager > ( ) ,
Substitute . For < ISmartDevice > ( ) ,
Substitute . For < IViewService > ( ) ,
Substitute . For < IBikesViewModel > ( ) ,
Substitute . For < IUser > ( ) ) ;
// Verify prerequisites.
Assert . AreEqual ( "Open lock & rent bike" , handler . ButtonText ) ;
Assert . IsFalse ( handler . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , handler . LockitButtonText ) ;
Assert . IsTrue ( handler . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Opens lock
/// Final state: Booked opened.
/// </summary>
[Test]
public void TestOpen ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Reading charging level..." ;
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert . AreEqual ( "Close lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( string . Empty , subsequent . LockitButtonText ) ;
Assert . That ( subsequent . IsLockitButtonVisible , Is . False ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsOutOfReachException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new OutOfReachException ( ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2023-08-31 12:20:06 +02:00
viewService . DisplayAdvancedAlert (
"Lock could not be opened!" ,
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again." ,
"Attention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to customer support (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station." ,
"OK"
) ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state "Booked Disconnected" after action
Assert . AreEqual ( nameof ( BookedDisconnected ) , subsequent . ButtonText ) ;
Assert . IsFalse ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsCouldntOpenBoltBlockedException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new CouldntOpenBoldIsBlockedException ( ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2023-08-31 12:20:06 +02:00
viewService . DisplayAdvancedAlert (
"Lock could not be opened!" ,
"Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again." ,
"Attention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to customer support (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station." ,
"OK"
) ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state "Booked Unknown" after action
Assert . AreEqual ( "Open lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsCouldntOpenInconsistentStateExecptionClosed ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new CouldntOpenInconsistentStateExecption ( LockingState . Closed ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2023-08-31 12:20:06 +02:00
viewService . DisplayAdvancedAlert (
"Lock could not be opened!" ,
"Lock reports it is still closed. Please try again!" ,
"Attention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to customer support (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station." ,
"OK"
) ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state "Booked Closed" after action
//Assert.AreEqual("End rental", subsequent.ButtonText);
//Assert.IsTrue(subsequent.IsButtonVisible);
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsCouldntOpenInconsistentStateExecption ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new CouldntOpenBoldStatusIsUnknownException ( ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2023-08-31 12:20:06 +02:00
viewService . DisplayAdvancedAlert (
"Lock could not be opened!" ,
"Position of lock bolt is unknown. Lock could be closed or open. Please try again!" ,
"Attention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to customer support (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station." ,
"OK" ) ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state "Booked Disconnected" after action
Assert . AreEqual ( "Open lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new Exception ( "Exception message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2023-08-31 12:20:06 +02:00
viewService . DisplayAdvancedAlert (
"Lock could not be opened!" ,
"Exception message." ,
"Please try again." ,
"OK"
) ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state "Booked Disconnected" after action
Assert . AreEqual ( nameof ( BookedDisconnected ) , subsequent . ButtonText ) ;
Assert . IsFalse ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Booked open.
/// </summary>
[Test]
public void TestOpenUpdateLockingStateFailsWebConnectFailureException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( LockitLockingState . Open ) ;
connector . Command . UpdateLockingStateAsync ( bike , null ) . Returns ( x = > throw new WebConnectFailureException ( "Context info" , new System . Exception ( "hoppla" ) ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Open ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Reading charging level..." ;
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
2023-04-05 15:02:10 +02:00
bikesViewModel . ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!" ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert . AreEqual ( "Close lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( string . Empty , subsequent . LockitButtonText ) ;
Assert . That ( subsequent . IsLockitButtonVisible , Is . False ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Booked open.
/// </summary>
[Test]
public void TestOpenUpdateLockingStateFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( LockitLockingState . Open ) ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = > throw new Exception ( "Exception message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Open ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Reading charging level..." ;
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "Connection error on updating locking status." ;
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert . AreEqual ( "Close lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( string . Empty , subsequent . LockitButtonText ) ;
Assert . That ( subsequent . IsLockitButtonVisible , Is . False ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Open lock
/// Final state: Booked open.
/// </summary>
[Test]
public void TestOpenUpdateLockingStateFailsResponseException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( LockitLockingState . Open ) ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = >
throw new ReturnBikeException ( JsonConvert . DeserializeObject < ReservationCancelReturnResponse > ( @"{ ""response_text"" : ""Some invalid data received!""}" ) , "Outer message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Open ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
2022-11-25 09:55:23 +01:00
bikesViewModel . ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>" ;
2022-09-06 16:08:19 +02:00
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Reading charging level..." ;
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "Status error on updating lock state." ;
bikesViewModel . ActionText = "Updating..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert . AreEqual ( "Close lock" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( string . Empty , subsequent . LockitButtonText ) ;
Assert . That ( subsequent . IsLockitButtonVisible , Is . False ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestClose ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) ) . Returns ( x = >
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
handler . ReportStep ( Step . UpdateLockingState ) ;
return Task . CompletedTask ;
2022-09-06 16:08:19 +02:00
}
2023-08-31 12:20:06 +02:00
) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Return lock state indicating success
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behavior
Received . InOrder ( ( ) = >
2022-09-06 16:08:19 +02:00
{
2023-08-31 12:20:06 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
bikesViewModel . ActionText = "Updating lock state..." ;
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
bikesViewModel . ActionText = string . Empty ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
// Verify state "Booked Closed" after action
Assert . AreEqual ( "End rental" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
[Test]
public void TestCloseCloseFailsOutOfReachException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) )
. Returns ( async x = >
2022-09-06 16:08:19 +02:00
{
2023-08-31 12:20:06 +02:00
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
await handler . ReportStateAsync ( CloseCommand . State . OutOfReachError , "" ) ;
throw new OutOfReachException ( ) ;
}
) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ;
bike . LockInfo . State . Returns ( LockingState . UnknownDisconnected ) ; /// If <see cref="OutOfReachException"/> is fired lock state is set to state unknown because disconnected.
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
// Verify behavior
Received . InOrder ( ( ) = >
2022-09-06 16:08:19 +02:00
{
2023-08-31 12:20:06 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
bikesViewModel . ActionText = string . Empty ;
viewService . DisplayAlert ( "Lock could not be closed!" , "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
bikesViewModel . ActionText = string . Empty ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
// Verify state "Booked disconnected" after action
Assert . AreEqual ( "Cancel reservation" , subsequent . ButtonText ) ;
Assert . That ( subsequent . IsButtonVisible , Is . True ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
/// <summary>
/// Use case: Close lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseCloseFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocationService > ( ) ;
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) ) . Returns ( async x = >
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
await handler . ReportStateAsync ( CloseCommand . State . GeneralCloseError , "Exception message." ) ;
throw new Exception ( "Exception message." ) ;
2022-09-06 16:08:19 +02:00
}
2023-08-31 12:20:06 +02:00
) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
bike . LockInfo . State . Returns ( LockingState . UnknownDisconnected ) ; // If CloseLock fires an exception of type Exception lock state is set to unknown.
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behavior
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
bikesViewModel . ActionText = string . Empty ;
viewService . DisplayAlert (
"Lock could not be closed!" ,
"Exception message." ,
"OK"
) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
bikesViewModel . ActionText = string . Empty ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Disconnected" after action
Assert . AreEqual ( "BookedDisconnected" , subsequent . ButtonText ) ;
Assert . IsFalse ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsWebConnectFailureException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
2023-04-05 15:02:10 +02:00
var geolocation = Substitute . For < IGeolocationService > ( ) ;
2022-09-06 16:08:19 +02:00
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
2023-08-31 12:20:06 +02:00
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) ) . Returns ( async x = >
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
handler . ReportStep ( Step . UpdateLockingState ) ;
await handler . ReportStateAsync ( State . WebConnectFailed , "Context info" ) ;
}
) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
2022-09-06 16:08:19 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating lock state..." ;
2023-04-05 15:02:10 +02:00
bikesViewModel . ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!" ;
2023-08-31 12:20:06 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Cancel reservation" , subsequent . ButtonText ) ;
2022-10-03 17:55:10 +02:00
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
2022-09-06 16:08:19 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
2023-04-05 15:02:10 +02:00
var geolocation = Substitute . For < IGeolocationService > ( ) ;
2022-09-06 16:08:19 +02:00
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
2023-08-31 12:20:06 +02:00
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) )
. Returns ( async x = >
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
handler . ReportStep ( Step . UpdateLockingState ) ;
await handler . ReportStateAsync ( CloseCommand . State . BackendUpdateFailed , "Exception message." ) ;
}
) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
2022-09-06 16:08:19 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating lock state..." ;
bikesViewModel . ActionText = "Connection error on updating locking status." ;
2023-08-31 12:20:06 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Cancel reservation" , subsequent . ButtonText ) ;
2022-10-03 17:55:10 +02:00
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
2022-09-06 16:08:19 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsResponseException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
2023-04-05 15:02:10 +02:00
var geolocation = Substitute . For < IGeolocationService > ( ) ;
2022-09-06 16:08:19 +02:00
var locks = Substitute . For < ILocksService > ( ) ;
var pollingManager = Substitute . For < IPollingUpdateTaskManager > ( ) ;
var viewService = Substitute . For < IViewService > ( ) ;
var bikesViewModel = Substitute . For < IBikesViewModel > ( ) ;
var activeUser = Substitute . For < IUser > ( ) ;
var handler = new ReservedUnknown (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
2023-08-31 12:20:06 +02:00
bike . CloseLockAsync ( Arg . Any < ICloseCommandListener > ( ) , Arg . Any < Task > ( ) )
. Returns ( async x = >
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler . ReportStep ( Step . ClosingLock ) ;
handler . ReportStep ( Step . UpdateLockingState ) ;
await handler . ReportStateAsync ( CloseCommand . State . ResponseIsInvalid , "Some invalid data received" ) ;
}
) ;
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ;
2022-09-06 16:08:19 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
2023-08-31 12:20:06 +02:00
pollingManager . StopAsync ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Stay with the bike until the lock is closed." ;
2022-09-06 16:08:19 +02:00
bikesViewModel . ActionText = "Updating lock state..." ;
bikesViewModel . ActionText = "Status error on updating lock state." ;
2023-08-31 12:20:06 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StartAsync ( ) ; // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel . ActionText = string . Empty ;
2022-09-06 16:08:19 +02:00
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Cancel reservation" , subsequent . ButtonText ) ;
2022-10-03 17:55:10 +02:00
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2023-08-31 12:20:06 +02:00
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
2022-09-06 16:08:19 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
}
2021-05-13 20:09:46 +02:00
}