2021-05-13 20:09:46 +02:00
using Newtonsoft.Json ;
using NSubstitute ;
using NUnit.Framework ;
using System ;
using System.Threading.Tasks ;
using TINK.Model.Bike.BluetoothLock ;
using TINK.Model.Bikes.Bike.BluetoothLock ;
using TINK.Model.Connector ;
2021-06-26 20:57:55 +02:00
using TINK.Repository.Exception ;
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 ;
using TINK.Model.Services.Geolocation ;
using TINK.Model.State ;
using TINK.View ;
using TINK.ViewModel ;
using TINK.ViewModel.Bikes ;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler ;
using TINK.Model.User ;
2021-06-26 20:57:55 +02:00
using TINK.Repository.Request ;
using TINK.Model.Device ;
2021-05-13 20:09:46 +02:00
namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
[TestFixture]
public class TestReservedClosed
{
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor ( )
{
var handler = new ReservedClosed (
Substitute . For < IBikeInfoMutable > ( ) ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > Substitute . For < IConnector > ( ) ,
Substitute . For < IGeolocation > ( ) ,
Substitute . For < ILocksService > ( ) ,
( ) = > Substitute . For < IPollingUpdateTaskManager > ( ) ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
Substitute . For < IViewService > ( ) ,
Substitute . For < IBikesViewModel > ( ) ,
Substitute . For < IUser > ( ) ) ;
// Verify prerequisites.
Assert . AreEqual ( "Cancel bike reservation" , handler . ButtonText ) ;
Assert . IsTrue ( handler . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , handler . LockitButtonText ) ;
Assert . IsTrue ( handler . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: User deceide to abort cancelling (user is ased whether to really cancel)
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationCancel ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( false ) ) ;
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
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Disposable.
/// </summary>
[Test]
public void TestCancelReservation ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Disposable ) ; // Reqesthandler factory queries state to create appropriate request handler object.
bike . LockInfo . State . Returns ( LockingState . Disconnected ) ; // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler . HandleRequestOption1 ( ) . 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 = "Canceling reservation..." ;
connector . Command . DoCancelReservation ( bike ) ; // Booking must be performed
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 after action
Assert . AreEqual ( "Reserve bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "DisposableDisconnected" , subsequent . LockitButtonText ) ;
Assert . IsFalse ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Exception is thrown.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationInvalidAuthorizationResponseException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
var response = JsonConvert . DeserializeObject < AuthorizationResponse > ( @ "
{
"" response "" : "" authorization "" ,
"" authcookie "" : "" 4d a3044c8657a04ba60e2eaa753bc51a "" ,
2021-06-26 20:57:55 +02:00
"" user_group "" : [ "" TINK "" , "" Konrad "" ] ,
2021-05-13 20:09:46 +02:00
"" response_state "" : "" OK "" ,
"" apiserver "" : "" https : //tinkwwp.copri-bike.de""
} ");
connector . Command . DoCancelReservation ( bike ) . Returns ( x = > throw new InvalidAuthorizationResponseException ( "mustermann@server.de" , response ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Reqesthandler factory queries state to create appropriate request handler object.
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Requsthandler factory queries lock state to create appropriate request handler object.
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 = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Canceling reservation..." ;
connector . Command . DoCancelReservation ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Fehler beim Aufheben der Reservierung!" , "Kann Benutzer mustermann@server.de nicht anmelden. Mailadresse unbekannt oder Passwort ungültig." , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationWebConnectFailureException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
connector . Command . DoCancelReservation ( bike ) . Returns ( x = > throw new WebConnectFailureException ( "Context info." , new Exception ( "chub" ) ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Reqesthandler factory queries state to create appropriate request handler object.
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Requsthandler factory queries lock state to create appropriate request handler object.
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 = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Canceling reservation..." ;
connector . Command . DoCancelReservation ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Verbingungsfehler beim Aufheben der Reservierung!" , "Context info.\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?" , "OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Cancel reservation for bike {0}?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
connector . Command . DoCancelReservation ( bike ) . Returns ( x = > throw new Exception ( "Exception message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Reqesthandler factory queries state to create appropriate request handler object.
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Requsthandler factory queries lock state to create appropriate request handler object.
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 = "One moment please..." ;
pollingManager . StopUpdatePeridically ( ) ; // Polling must be stopped before any COPR and lock service action
bikesViewModel . ActionText = "Canceling reservation..." ;
connector . Command . DoCancelReservation ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "" ;
viewService . DisplayAlert ( "Fehler beim Aufheben der Reservierung!" , "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 after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: user cancels operation.
/// Final state: Reserved and closed.
/// </summary>
[Test]
public void TestBookAndOpenCancelBook ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( false ) ) ;
var subsequent = handler . HandleRequestOption2 ( ) . 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 ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpen ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to 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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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: Open lock and book bike.
/// Comment: COPRI request to book bike fails (WebConnectFailureException). Lock is opened and closed again.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestBookAndOpenBookingFailsWebConnectFailureException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Locking state does not change.
connector . Command . DoBook ( bike ) . Returns ( x = > throw new WebConnectFailureException ( "Context info" , new Exception ( "Tst" ) ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // State remains reserved because booking request failed.
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "" ;
viewService . DisplayAdvancedAlert (
"Connection error when renting the bike!" ,
"Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?" ,
"Context info" ,
"OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "reserved closed" after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: COPRI request to book bike fails (Exception). Lock is opened and closed again.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestBookAndOpenBookingFailsException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
bike . LockInfo . State . Returns ( LockingState . Closed ) ; // Locking state does not change.
connector . Command . DoBook ( bike ) . Returns ( x = > throw new Exception ( "Exception message." ) ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // When booking fails state remains reserved.
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "" ;
viewService . DisplayAdvancedAlert (
"Error when renting the bike!" ,
"" ,
"Exception message." ,
"OK" ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state "reserved closed" after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Open lock & rent bike" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike,
/// Comment: Unlocking bike throws an OutOfReach-Exception.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestBookAndOpenOpenFailsExceptionOutOfReachException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > { throw new OutOfReachException ( ) ; } ) ;
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Booking call leads to setting of state to booked.
bike . LockInfo . State . Returns ( LockingState . Unknown ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "" ;
2021-06-26 20:57:55 +02:00
viewService . DisplayAlert ( "Error while opening lock!" , "Lock cannot be opened until bike is near." , "OK" ) ;
2021-05-13 20:09: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 after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: Unlocking bike throws an exception.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestBookAndOpenOpenFailsException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns < Task < LockitLockingState ? > > ( x = > throw new Exception ( "Exception message." ) ) ; // Return lock state indicating success
2021-06-26 20:57:55 +02:00
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Booking call leads to setting of state to booked.
2021-05-13 20:09:46 +02:00
bike . LockInfo . State . Returns ( LockingState . Unknown ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "" ;
2021-06-26 20:57:55 +02:00
viewService . DisplayAlert ( "Error while opening lock!" , "Exception message." , "OK" ) ;
2021-05-13 20:09: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 after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: Unlocking bike does not return state bike opened.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestBookAndOpenOpenFailsNotOpen ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) null ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Reserved ) ; // Booking state does not change.
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
bikesViewModel . Received ( 1 ) . IsIdle = true ; // GUI must be unlocked
} ) ;
// Verify state after action
Assert . AreEqual ( "Cancel bike reservation" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Search lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
/// <summary>
/// Use case: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpenBatteryPercentageOutOfReachException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to booked.
locks [ 0 ] . GetBatteryPercentageAsync ( ) . Returns < Task < double > > ( x = > throw new OutOfReachException ( ) ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
bikesViewModel . ActionText = "Battery status can only be read when bike is nearby." ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpenBatteryPercentageException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to booked.
locks [ 0 ] . GetBatteryPercentageAsync ( ) . Returns < Task < double > > ( x = > throw new Exception ( ) ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
bikesViewModel . ActionText = "Battery status cannot be read." ;
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
bikesViewModel . ActionText = "Updating..." ;
pollingManager . StartUpdateAyncPeridically ( ) ; // polling must be restarted again
bikesViewModel . ActionText = "" ;
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: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpenUpdateLockingStateFailsWebConnectFailureException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to booked.
connector . Command . UpdateLockingStateAsync ( bike , null ) . Returns ( x = > throw new WebConnectFailureException ( "Context info" , new System . Exception ( "hoppla" ) ) ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
bikesViewModel . ActionText = "Updating lock state..." ;
connector . Command . UpdateLockingStateAsync ( bike , null ) ;
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 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: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpenUpdateLockingStateFailsException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to booked.
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = > throw new Exception ( "Exception message." ) ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
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 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: Open lock and book bike.
/// Comment: Bike gets opened.
/// Final state: Booked open.
/// </summary>
[Test]
public void TestBookAndOpenUpdateLockingStateFailsResponseException ( )
{
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 ReservedClosed (
bike ,
( ) = > true , // isConnectedDelegate
( isConnexted ) = > connector ,
geolocation ,
locks ,
( ) = > pollingManager ,
2021-06-26 20:57:55 +02:00
Substitute . For < ISmartDevice > ( ) ,
2021-05-13 20:09:46 +02:00
viewService ,
bikesViewModel ,
activeUser ) ;
2021-06-26 20:57:55 +02:00
bike . Id . Returns ( "0" ) ;
2021-05-13 20:09:46 +02:00
viewService . DisplayAlert ( string . Empty , string . Format ( "Rent bike {0} and open lock?" , "Nr. 0" ) , "Yes" , "No" ) . Returns ( Task . FromResult ( true ) ) ;
locks [ 0 ] . OpenAsync ( )
. Returns ( Task . FromResult ( ( LockitLockingState ? ) LockitLockingState . Open ) ) ; // Return lock state indicating success
bike . State . Value . Returns ( InUseStateEnum . Booked ) ; // Booking call leads to setting of state to booked.
connector . Command . UpdateLockingStateAsync ( bike , Arg . Any < LocationDto > ( ) ) . Returns ( x = >
throw new ReturnBikeException ( JsonConvert . DeserializeObject < ReservationCancelReturnResponse > ( @"{ ""response_text"" : ""Some invalid data received!""}" ) , "Outer message." ) ) ;
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 = "Renting bike..." ;
connector . Command . DoBook ( bike ) ; // Booking must be performed
bikesViewModel . ActionText = "Opening lock..." ;
locks . Received ( ) [ 0 ] . OpenAsync ( ) ; // Lock must be opened
bikesViewModel . ActionText = "Reading charging level..." ;
2021-06-26 20:57:55 +02:00
locks [ 0 ] . GetBatteryPercentageAsync ( ) ;
2021-05-13 20:09:46 +02:00
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 after action
Assert . AreEqual ( "Close lock & return bike" , subsequent . ButtonText ) ;
Assert . IsTrue ( subsequent . IsButtonVisible ) ;
Assert . AreEqual ( "Close lock" , subsequent . LockitButtonText ) ;
Assert . IsTrue ( subsequent . IsLockitButtonVisible ) ;
}
}
}