2022-08-30 15:42:25 +02:00
using System ;
using System.Threading ;
using System.Threading.Tasks ;
using Newtonsoft.Json ;
2021-07-12 21:31:46 +02:00
using NSubstitute ;
2022-08-30 15:42:25 +02:00
using NUnit.Framework ;
using TINK.Model ;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock ;
2021-07-12 21:31: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 ;
using TINK.Repository.Exception ;
using TINK.Repository.Request ;
using TINK.Repository.Response ;
2021-07-12 21:31:46 +02:00
using TINK.Services.BluetoothLock ;
2022-08-30 15:42:25 +02:00
using TINK.Services.BluetoothLock.Exception ;
using TINK.Services.BluetoothLock.Tdo ;
2022-04-10 17:38:34 +02:00
using TINK.Services.Geolocation ;
2021-07-12 21:31:46 +02:00
using TINK.View ;
using TINK.ViewModel ;
using TINK.ViewModel.Bikes ;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler ;
using Xamarin.Essentials ;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
[TestFixture]
public class TestBookedOpen
{
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor ( )
{
var handler = new BookedOpen (
Substitute . For < IBikeInfoMutable > ( ) ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > Substitute . For < IConnector > ( ) ,
Substitute . For < IGeolocation > ( ) ,
Substitute . For < ILocksService > ( ) ,
( ) = > Substitute . For < IPollingUpdateTaskManager > ( ) ,
Substitute . For < ISmartDevice > ( ) ,
Substitute . For < IViewService > ( ) ,
Substitute . For < IBikesViewModel > ( ) ,
Substitute . For < IUser > ( ) ) ;
// Verify prerequisites.
Assert . AreEqual ( "Close lock & return bike" , handler . ButtonText ) ;
Assert . IsTrue ( handler . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , handler . LockitButtonText ) ;
Assert . IsTrue ( handler . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Comment: User cancels operation.
/// Final state: Booked and open.
/// Similar to TestReservedClosed::TestBookAndOpenCancelBook
/// </summary>
[Test]
public void TestCloseAndReturnCancelReturn ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0 Allround Mono?" , "Yes" , "No" ) . Returns ( Task . FromResult ( false ) ) ;
2021-07-12 21:31:46 +02:00
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Disposable closed.
/// Similar to TestReservedClosed::TestBookAndOpen
/// </summary>
[Test]
public void TestCloseAndReturn ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Closed ) ) ; // Return lock state indicating success
2021-08-28 10:04:10 +02:00
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) . Returns ( Task . FromResult ( new Location ( 1 , 2 ) ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Disposable ) ; // Return call leads to setting of state to disposable.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2021-08-28 10:04:10 +02:00
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ; // Geolocation must be retrieved
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2022-08-30 15:42:25 +02:00
connector . Command . DoReturn ( bike , Arg . Is < LocationDto > ( x = > x . Latitude = = 1 & & x . Longitude = = 2 ) , Arg . Any < ISmartDevice > ( ) ) ; // Booking must be performed
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Disconnecting lock..." ;
locks . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Disposable Closed" after action
Assert . AreEqual ( "Reserve bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "DisposableDisconnected" , subsequent . LockitButtonText ) ;
Assert . IsFalse ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseAndReturnCloseFailsOutOfReachException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
2022-08-30 15:42:25 +02:00
. Returns < LockitLockingState ? > ( x = > throw new OutOfReachException ( ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "" ;
2022-04-10 17:38:34 +02:00
bike . LockInfo . State = LockingState . UnknownDisconnected ;
connector . Command . UpdateLockingStateAsync ( Arg . Any < IBikeInfoMutable > ( ) ) ;
2021-07-12 21:31:46 +02:00
viewService . DisplayAlert ( "Lock can not be closed!" , "Lock cannot be closed until bike is near." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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-04-10 17:38:34 +02:00
[Test]
public void TestCloseAndReturnStartReturningBikeWebConnectFailureException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
connector . Command . StartReturningBike ( bike ) . Returns ( x = > throw new WebConnectFailureException ( "Context info" , new Exception ( "hoppla" ) ) ) ;
bike . LockInfo . State . Returns ( LockingState . Open ) ; // If locking fails bike remains open.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
bikesViewModel . ActionText = "" ;
viewService . DisplayAdvancedAlert (
"Connection error when returning the bike!" ,
"Internet must be available when returning the bike.\r\nIs WIFI available/ mobile networt available and mobile data activated / ... ?" ,
"Context info" ,
"OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked open" after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
[Test]
public void TestCloseAndReturnStartReturningBikeException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
connector . Command . StartReturningBike ( bike ) . Returns ( x = > throw new Exception ( "Context info" , new Exception ( "hoppla" ) ) ) ;
bike . LockInfo . State . Returns ( LockingState . Open ) ; // If locking fails bike remains open.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert (
"Error returning bike!" ,
"Context info" ,
"OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked open" after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
2021-07-12 21:31:46 +02:00
/// <summary>
/// Use case: Close lock and return.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseAndReturnCloseFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
2022-04-10 17:38:34 +02:00
. Returns < LockitLockingState ? > ( x = > throw new Exception ( "Blu" ) ) ;
2021-07-12 21:31:46 +02:00
bike . LockInfo . State . Returns ( LockingState . Open ) ; // If locking fails bike remains open.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "" ;
2022-04-10 17:38:34 +02:00
bike . LockInfo . State = LockingState . UnknownDisconnected ;
connector . Command . UpdateLockingStateAsync ( Arg . Any < IBikeInfoMutable > ( ) ) ;
2021-07-12 21:31:46 +02:00
viewService . DisplayAlert ( "Lock can not be closed!" , "Blu" , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked open" after action
Assert . AreEqual ( "BookedDisconnected" , subsequent . ButtonText ) ;
Assert . IsFalse ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Same as initial state.
/// </summary>
[Test]
2022-04-10 17:38:34 +02:00
public void TestCloseAndReturnCloseFailsCouldntCloseMovingException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . CloseAsync ( )
2022-08-30 15:42:25 +02:00
. Returns < LockitLockingState ? > ( x = > throw new CouldntCloseMovingException ( ) ) ;
2022-04-10 17:38:34 +02:00
//bike.LockInfo.State.Returns(LockingState.Open); // If locking fails bike remains open.
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "" ;
bike . LockInfo . State = LockingState . Open ;
connector . Command . UpdateLockingStateAsync ( Arg . Any < IBikeInfoMutable > ( ) ) ;
viewService . DisplayAlert (
"Lock can not be closed!" ,
"Lock can only be closed if bike is not moving. Please park bike and try again." ,
"OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked open" after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseAndReturnCloseFailsNotClosed ( )
2021-07-12 21:31:46 +02:00
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
2022-08-30 15:42:25 +02:00
. Returns ( LockitLockingState . Open ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2022-04-10 17:38:34 +02:00
bike . LockInfo . State = LockingState . Open ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
2022-04-10 17:38:34 +02:00
connector . Command . UpdateLockingStateAsync ( Arg . Any < IBikeInfoMutable > ( ) ) ;
2021-07-12 21:31:46 +02:00
viewService . DisplayAlert ( "Lock can not be closed!" , "After try to close lock state open is reported." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked open" after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
2021-08-28 10:04:10 +02:00
public async Task TestCloseAndReturnGetGeolocationFailsException ( )
2021-07-12 21:31:46 +02:00
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
2021-08-28 10:04:10 +02:00
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) . Returns ( Task . FromException < Location > ( new Exception ( "noloc" ) ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
2021-08-28 10:04:10 +02:00
var subsequent = await handler . HandleRequestOption1 ( ) ;
2021-07-12 21:31:46 +02:00
2021-08-28 10:04:10 +02:00
await locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
2021-07-12 21:31:46 +02:00
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAdvancedAlert ( "Error Query Location!" , "Closing the lock and ending the rental is not possible." , "noloc" , "OK" ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
public void TestCloseAndReturnReturnFailsWebConnectFailureException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
2022-01-04 18:54:03 +01:00
connector . Command . DoReturn ( bike , Arg . Any < LocationDto > ( ) , Arg . Any < ISmartDevice > ( ) ) . Returns < BookingFinishedModel > ( x = > throw new WebConnectFailureException ( "Context info" , new System . Exception ( "hoppla" ) ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAdvancedAlert (
"Connection error when returning the bike!" ,
2022-04-10 17:38:34 +02:00
"Internet must be available when returning the bike.\r\nIs WIFI available/ mobile networt available and mobile data activated / ... ?" ,
2021-08-28 10:04:10 +02:00
"Context info" ,
"OK" ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
public void TestCloseAndReturnReturnFailsException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
2022-01-04 18:54:03 +01:00
connector . Command . DoReturn ( bike , Arg . Any < LocationDto > ( ) , Arg . Any < ISmartDevice > ( ) ) . Returns < BookingFinishedModel > ( x = > throw new System . Exception ( "Exception message." ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
2022-04-10 17:38:34 +02:00
viewService . DisplayAlert ( "Error returning bike!" , "Exception message." , "OK" ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
public void TestCloseAndReturnReturnFailsNotAtStationException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
NotAtStationException . IsNotAtStation ( "Failure 2178: bike 1545 out of GEO fencing. 15986 meter distance to next station 77. OK: bike 1545 locked confirmed" , out NotAtStationException notAtStationException ) ;
2022-01-04 18:54:03 +01:00
connector . Command . DoReturn ( bike , Arg . Any < LocationDto > ( ) , Arg . Any < ISmartDevice > ( ) ) . Returns < BookingFinishedModel > ( x = >
2021-07-12 21:31:46 +02:00
throw notAtStationException ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Error returning bike!" , "Returning bike outside of station is not possible. Distance to station 77 is 15986 m." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
public void TestCloseAndReturnReturnFailsNoGPSDataException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
NoGPSDataException . IsNoGPSData ( "Failure 2245: No GPS data, state change forbidden." , out NoGPSDataException noGPSDataException ) ;
2022-01-04 18:54:03 +01:00
connector . Command . DoReturn ( bike , Arg . Any < LocationDto > ( ) , Arg . Any < ISmartDevice > ( ) ) . Returns < BookingFinishedModel > ( x = >
2021-07-12 21:31:46 +02:00
throw noGPSDataException ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Error returning bike!" , "Returning bike at an unknown location is not possible.\r\nBike can only be returned if bike is in reach and location information is available." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock and return.
/// Final state: Booked locked.
/// </summary>
[Test]
public void TestCloseAndReturnReturnFailsResponseException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
bike . Id . Returns ( "0" ) ;
2021-08-28 10:04:10 +02:00
viewService . DisplayAlert ( string . Empty , "Close lock and return bike Nr. 0?" , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
2021-07-12 21:31:46 +02:00
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ;
2022-01-04 18:54:03 +01:00
connector . Command . DoReturn ( bike , Arg . Any < LocationDto > ( ) , Arg . Any < ISmartDevice > ( ) ) . Returns < BookingFinishedModel > ( x = >
throw new ReturnBikeException ( JsonConvert . DeserializeObject < DoReturnResponse > ( @"{ ""response_text"" : ""Some invalid data received!""}" ) , "Outer message." ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking state remains unchanged if closing fails.
var subsequent = handler . HandleRequestOption1 ( ) . Result ;
2022-08-30 15:42:25 +02:00
2021-07-12 21:31:46 +02:00
locks . DidNotReceive ( ) . DisconnectAsync ( Arg . Any < int > ( ) , Arg . Any < Guid > ( ) ) ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Start query location..." ;
geolocation . GetAsync ( Arg . Any < CancellationToken ? > ( ) , Arg . Any < DateTime > ( ) ) ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
2022-04-10 17:38:34 +02:00
bikesViewModel . ActionText = "Starting bike return..." ;
connector . Command . StartReturningBike ( bike ) ; // Notify about start
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
2021-08-28 10:04:10 +02:00
bikesViewModel . ActionText = "Query location..." ;
bikesViewModel . ActionText = "Returning bike..." ;
2021-07-12 21:31:46 +02:00
bikesViewModel . ActionText = "" ;
viewService . DisplayAdvancedAlert ( "Statusfehler beim Zurückgeben des Rads!" , "Outer message." , "Some invalid data received!" , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <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 < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Closed ) ) ; // Return lock state indicating success
2022-08-30 15:42:25 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
2021-07-12 21:31:46 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Close lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseCloseFailsOutOfReachException ( )
{
var bike = Substitute . For < IBikeInfoMutable > ( ) ;
var connector = Substitute . For < IConnector > ( ) ;
var command = Substitute . For < ICommand > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
2022-08-30 15:42:25 +02:00
. Returns < Task < LockitLockingState ? > > ( x = > throw new OutOfReachException ( ) ) ;
2021-07-12 21:31:46 +02:00
2022-08-30 15:42:25 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
2021-07-12 21:31:46 +02:00
bike . LockInfo . State . Returns ( LockingState . Open ) ;
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Lock can not be closed!" , "Lock cannot be closed until bike is near." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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 ) ;
}
/// <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 < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
2022-08-30 15:42:25 +02:00
. Returns < Task < LockitLockingState ? > > ( x = > throw new Exception ( "Exception message." ) ) ;
2021-07-12 21:31:46 +02:00
2022-08-30 15:42:25 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
2021-07-12 21:31:46 +02:00
bike . LockInfo . State . Returns ( LockingState . Open ) ;
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Lock can not be closed!" , "Exception message." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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 ) ;
}
/// <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 > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ; // Return lock state indicating success
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = > throw new WebConnectFailureException ( "Context info" , new System . Exception ( "hoppla" ) ) ) ;
2022-08-30 15:42:25 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
2021-07-12 21:31:46 +02:00
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "No web error on updating locking status." ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +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 > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ; // Return lock state indicating success
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = > throw new Exception ( "Exception message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "Connection error on updating locking status." ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +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 > ( ) ;
var geolocation = Substitute . For < IGeolocation > ( ) ;
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 BookedOpen (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
Substitute . For < ISmartDevice > ( ) ,
viewService ,
bikesViewModel ,
activeUser ) ;
locks [ 0 ] . CloseAsync ( )
. Returns ( LockitLockingState . Closed ) ; // Return lock state indicating success
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = >
2021-12-08 17:57:30 +01:00
throw new ReturnBikeException ( JsonConvert . DeserializeObject < DoReturnResponse > ( @"{ ""response_text"" : ""Some invalid data received!""}" ) , "Outer message." ) ) ;
2021-07-12 21:31:46 +02:00
bike . State . Value . Returns ( InUseStateEnum . Booked ) ;
var subsequent = handler . HandleRequestOption2 ( ) . Result ;
// Verify behaviour
Received . InOrder ( ( ) = >
{
bikesViewModel . Received ( 1 ) . IsIdle = false ; // GUI must be locked
bikesViewModel . ActionText = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Closing lock..." ;
locks . Received ( ) [ 0 ] . CloseAsync ( ) ; // Lock must be closed
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) ;
bikesViewModel . ActionText = "Status error on updating lock state." ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "Booked Closed" after action
Assert . AreEqual ( "Return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
2022-06-17 14:17:58 +02:00
Assert . AreEqual ( "Open lock" , subsequent . LockitButtonText ) ;
2021-07-12 21:31:46 +02:00
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
}
}