Version 3.0.370

This commit is contained in:
Anja 2023-08-31 12:20:06 +02:00
parent f5cf9bb22f
commit bdb2dec1c1
233 changed files with 10252 additions and 6779 deletions

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
@ -23,6 +22,7 @@ using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
@ -58,9 +58,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks> Replaces test TestReturnOutOfReach which was removed for sharee.bike verion ~3.0.362. </remarks>
/// <remarks> Replaces test TestReturnOutOfReach which was removed for sharee.bike version ~3.0.362. </remarks>
[Test]
public void TestReturnLastGeolocatonNullLockOfOfReach()
public void TestReturnLastGeolocatonNullLockOutOfReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
@ -86,11 +86,14 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Disconnected); // Simulate bike out of reach.
locks.DisconnectAsync(0, Arg.Any<Guid>()).Returns(LockingState.UnknownDisconnected); // Simulate disconnecting.
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Throws((x) =>
{
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand.State.DisconnetedNoLocationError, "").Wait();
handler.ReportStep(Step.DisconnectingLockOnDisconnectedNoLocationError);
handler.ReportStateAsync(TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand.State.QueryLocationSucceeded, "").Wait();
throw new Exception();
});
bike.State.Value.Returns(InUseStateEnum.Booked);
@ -100,13 +103,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
locks[0].GetDeviceState();
viewService.DisplayAlert(
"Error at ending rental!",
"We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!\r\n\r\nApproach the bike, turn on Bluetooth and Location services and try again.",
"Rental could not be terminated!",
"We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!\r\n\r\nApproach the bike lock, turn on Bluetooth and Location services and try again.",
"OK");
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(0, Arg.Any<Guid>());
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -150,79 +151,29 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Throws(new Exception("Ups...")); // Simulate error when starting query for geolocation.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behavior
Received.InOrder(() =>
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Throws((x) =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
locks[0].GetDeviceState();
bikesViewModel.ActionText = "Start query location...";
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
viewService.DisplayAlert(
"Error at ending rental!",
"End rental at an unknown location is not possible.\r\nStart getting geolocation failed.",
"OK");
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand.State.QueryLocationFailed, "Ups...").Wait();
throw new Exception();
});
// Verify state after action
Assert.AreEqual("End rental", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
/// <summary>
/// Use case: End rental.
/// Comment: User decide to abort returning bike
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestReturnCancel()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new BookedClosed(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(false));
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No");
bikesViewModel.ActionText = "Query location...";
viewService.DisplayAlert(
"Rental could not be terminated!",
"Grant Location permission, activate Location services and try again.",
"OK");
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -264,14 +215,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>())
.Returns((x) =>
{
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand.State.QueryLocationFailed, "Ups...").Wait();
return Task.FromException<LocationDto>(new Exception("Ups..."));
});
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromException<IGeolocation>(new Exception("Ups..."))); // Simulate error starting query for geolocation.
var subsequent = handler.HandleRequestOption1().Result;
@ -279,14 +234,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
locks[0].GetDeviceState();
bikesViewModel.ActionText = "Start query location...";
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
bikesViewModel.ActionText = "Query location...";
viewService.DisplayAlert(
"Location query failed",
"End rental at an unknown location is not possible.\r\nMake sure you have granted location sharing permission and your location services are enabled.\r\nTry again!",
"Rental could not be terminated!",
"Grant Location permission, activate Location services and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -327,24 +279,19 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
bike.LockInfo.Location.Returns((IGeolocation)null);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Returns((x) =>
{
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand.State.QueryLocationSucceeded, string.Empty).Wait();
return Task.FromResult(new LocationDto.Builder().Build());
});
var location = Substitute.For<IGeolocation>();
location.Latitude.Returns(7);
location.Longitude.Returns(9);
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime>()).Returns(Task.FromResult(
location
)); ;
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
bike.State.Value.Returns(InUseStateEnum.Disposable); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
@ -352,16 +299,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Query location...";
bikesViewModel.ActionText = "Ending rental...";
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x != null));
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -424,17 +370,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "Ending rental...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Connection error when ending rental.",
"Internet must be available when ending rental. Please establish an Internet connection!\r\nIs WIFI/mobile network available and mobile data activated?",
"Context info",
viewService.DisplayAlert(
"Rental could not be terminated!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -498,13 +442,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "Ending rental...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error at ending rental!", "End rental outside of station is not possible. Distance to station 42 is 15986 m.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
viewService.DisplayAlert("Rental could not be terminated!", "End rental outside or at wrong station is not possible. Distance to next suitable station 42 is 15986 m.", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -568,13 +511,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "Ending rental...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error at ending rental!", "End rental at an unknown location is not possible.\r\nRental can be ended if\r\n- location information is available when closing lock\r\n- bike is in reach and location information is available when pressing button \"End rental\"", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
viewService.DisplayAlert("Rental could not be terminated!", "End rental at an unknown location is not possible.\r\nRental can be ended if\r\n- location information is available when closing lock\r\n- bike is in reach and location information is available when pressing button \"End rental\"", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -636,13 +578,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "Ending rental...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
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
viewService.DisplayAdvancedAlert("Rental could not be terminated!", "Outer message.", "Some invalid data received!", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -691,8 +632,8 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
@ -703,13 +644,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "Ending rental...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error at ending rental!", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
viewService.DisplayAlert(
"Rental could not be terminated!",
"Exception message.",
"OK"
);
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -762,7 +706,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -770,16 +714,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -824,13 +768,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Lock cannot be opened until bike is near.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -847,7 +791,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsCouldntOpenBoldBlockedException()
public void TestOpenOpenFailsCouldntOpenBoltBlockedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
@ -884,13 +828,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Ensure that no obstacle prevents lock from opening and try again.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -945,13 +889,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "After try to open lock state closed is reported.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Lock reports it is still closed. Please try again!", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -1005,13 +949,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Lock can not be opened!", "The lock could not be opened correctly. Try again!\r\n\r\nAttention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to the operator (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Position of lock bolt is unknown. Lock could be closed or open. Please try again!", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -1065,13 +1009,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Exception message.", "OK");
viewService.DisplayAdvancedAlert(
"Lock could not be opened!",
"Exception message.",
"Please try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -1126,7 +1075,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -1135,16 +1084,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1190,7 +1139,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -1199,16 +1148,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Closed" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1255,7 +1204,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -1264,16 +1213,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1320,7 +1269,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -1329,16 +1278,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1386,7 +1335,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -1395,16 +1344,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
}
}

View file

@ -125,22 +125,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -184,12 +184,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting with lock!", "Internet must be reachable to connect to lock of rented bike. Please establish an Internet connection!\r\nContext info\r\nIs WIFI/mobile network available and mobile data activated?", "OK");
viewService.DisplayAlert(
"Connection to booking system not possible.",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -242,12 +246,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting with lock!", "Communication error during lock search.\r\nException message.", "OK");
viewService.DisplayAlert("Connection to the lock could not be established.", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -302,19 +306,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Error when connecting with lock!",
"Lock can only be found when rented bike is nearby.",
"Retry",
"Cancel");
"Connection to the lock could not be established.",
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -369,20 +372,20 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Error when connecting with lock!",
"Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.",
"Connection to the lock could not be established.",
"Please step as close as possible to the bike lock and try again.",
"",
"Retry",
"Cancel");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -438,15 +441,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting with lock!", "Schlossstatus des gemieteten Rads konnte nicht ermittelt werden.", "OK");
viewService.DisplayAlert("Connection to the lock could not be established.", "Lock status could not be determined. Please contact customer support.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});

View file

@ -4,6 +4,7 @@ using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.State;
@ -19,6 +20,7 @@ using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
@ -92,7 +94,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -100,16 +102,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -154,13 +156,13 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Lock cannot be opened until bike is near.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -177,7 +179,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestOpenOpenFailsCouldntOpenBoldBlockedException()
public void TestOpenOpenFailsCouldntOpenBoltBlockedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
@ -214,13 +216,13 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Ensure that no obstacle prevents lock from opening and try again.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -274,13 +276,13 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "After try to open lock state closed is reported.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Lock reports it is still closed. Please try again!", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -334,13 +336,13 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Lock can not be opened!", "The lock could not be opened correctly. Try again!\r\n\r\nAttention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to the operator (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station.", "OK");
viewService.DisplayAlert("Lock could not be opened!", "Position of lock bolt is unknown. Lock could be closed or open. Please try again!", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -394,13 +396,17 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Exception message.", "OK");
viewService.DisplayAdvancedAlert(
"Lock could not be opened!",
"Exception message.",
"Please try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -455,7 +461,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -464,16 +470,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
@ -520,7 +526,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -529,16 +535,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -585,7 +591,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -594,16 +600,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -650,7 +656,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -659,16 +665,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -716,7 +722,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be closed
bikesViewModel.ActionText = "Reading charging level...";
@ -725,16 +731,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "Booked Open" after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -766,10 +772,17 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel,
activeUser);
locks[0].CloseAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed); // Return lock state indicating success
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
return Task.CompletedTask;
}
);
var subsequent = handler.HandleRequestOption2().Result;
@ -778,13 +791,11 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -825,11 +836,18 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel,
activeUser);
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(CloseCommand.State.OutOfReachError, "");
throw new OutOfReachException();
}
);
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); /// If <see cref="OutOfReachException"/> is fired lock state is set to state unknown because disconnected.
var subsequent = handler.HandleRequestOption2().Result;
@ -838,13 +856,12 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Lock can not be closed!", "Lock cannot be closed until bike is near.", "OK");
viewService.DisplayAlert("Lock could not be closed!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -885,11 +902,17 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel,
activeUser);
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(State.GeneralCloseError, "Exception message.");
throw new Exception("Exception message.");
}
);
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // If CloseLock fires an exception of type Exception lock state is set to unknown.
var subsequent = handler.HandleRequestOption2().Result;
@ -898,13 +921,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Lock can not be closed!", "Exception message.", "OK");
viewService.DisplayAlert(
"Lock could not be closed!",
"Exception message.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -945,12 +971,17 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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")));
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.WebConnectFailed, "Context info");
}
);
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
var subsequent = handler.HandleRequestOption2().Result;
@ -959,14 +990,12 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -1007,12 +1036,18 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.BackendUpdateFailed, "Exception message.");
}
);
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
var subsequent = handler.HandleRequestOption2().Result;
@ -1021,14 +1056,12 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = "Updating lock state...";
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 = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -1069,13 +1102,18 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel,
activeUser);
locks[0].CloseAsync()
.Returns(LockitLockingState.Closed); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x =>
throw new ReturnBikeException(JsonConvert.DeserializeObject<ReservationCancelReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.ResponseIsInvalid, "Some invalid data received");
}
);
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
var subsequent = handler.HandleRequestOption2().Result;
@ -1084,14 +1122,12 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
locks.Received()[0].CloseAsync(); // Lock must be closed
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
bikesViewModel.ActionText = "Updating lock state...";
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 = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});

View file

@ -154,7 +154,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = "Searching lock...";
@ -169,16 +169,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -228,13 +228,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Hint", string.Format("A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/rentals had already been made.", 0, 7), "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -293,13 +293,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Connection error when reserving the bike!", "Context info.\r\nIs WIFI/mobile network available and mobile data activated?", "OK");
viewService.DisplayAlert("Connection to booking system not possible.", "A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -358,13 +358,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when reserving the bike!", "Exception message.", "OK");
viewService.DisplayAdvancedAlert(
"Bike could not be reserved!",
"Exception message.",
"Please try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -425,20 +430,20 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Lock out of reach";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -493,20 +498,20 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Lock not found";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -560,19 +565,19 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike); // Booking must be performed
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);

View file

@ -42,7 +42,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Rent bike or close lock", handler.ButtonText);
Assert.AreEqual("Close lock or rent bike", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual(nameof(DisposableOpen), handler.LockitButtonText);
Assert.IsFalse(handler.IsLockitButtonVisible);
@ -77,7 +77,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
@ -90,13 +92,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -137,7 +139,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
@ -153,13 +157,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Lock can not be closed!", "Lock cannot be closed until bike is near.", "OK");
viewService.DisplayAlert("Lock could not be closed!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -200,7 +204,9 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
@ -216,13 +222,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Lock can not be closed!", "Exception message.", "OK");
viewService.DisplayAdvancedAlert(
"Lock could not be closed!",
"Exception message.",
"Please try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -265,7 +276,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
@ -277,27 +288,27 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Disposabled Closed.
/// Final state: Disposable Closed.
/// </summary>
[Test]
public void TestDoBookDoBookFailsWebConnectFailureException()
@ -326,7 +337,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
connector.Command.DoBookAsync(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
@ -341,22 +352,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Connection error when renting the bike!",
string.Format("Attention: Lock is closed!\r\n{0}\r\n{1}", "Context info.", "Is WIFI/mobile network available and mobile data activated?"),
"Bike could not be rented!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Verschließe Schloss...";
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -370,7 +381,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
/// <summary>
/// Use case: Lock bike.
/// Final state: Disposabled Closed.
/// Final state: Disposable Closed.
/// </summary>
[Test]
public void TestDoBookDoBookFailsException()
@ -399,7 +410,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
connector.Command.DoBookAsync(bike).Returns(x => throw new Exception("Exception message."));
@ -414,19 +425,19 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when renting the bike!", "Attention: Lock is closed!\r\nException message.", "OK");
bikesViewModel.ActionText = "Verschließe Schloss...";
viewService.DisplayAlert("Bike could not be rented!", "Exception message.", "OK");
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});

View file

@ -44,7 +44,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -97,7 +97,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -145,13 +145,13 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // 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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -219,22 +219,22 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
"Can not login user mustermann@server.de. Mail address unknown or password invalid.",
"Reservation could not be canceled!",
"Your session has expired. Please login new and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -287,22 +287,22 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Connection error when canceling the reservation!",
"Context info.\r\nIs WIFI/mobile network available and mobile data activated?",
"Reservation could not be canceled!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -355,22 +355,23 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
viewService.DisplayAdvancedAlert(
"Reservation could not be canceled!",
"Exception message.",
"Please try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -418,7 +419,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -470,7 +471,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -480,16 +481,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -539,23 +540,22 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Connection error when renting the bike!",
"Is WIFI/mobile network available and mobile data activated?",
"Context info",
viewService.DisplayAlert(
"Bike could not be rented!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "reserved closed" after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -608,23 +608,23 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Error when renting the bike!",
"",
"Bike could not be rented!",
"Please try again.",
"Exception message.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state "reserved closed" after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -677,21 +677,26 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Lock cannot be opened until bike is near.", "OK");
viewService.DisplayAdvancedAlert(
"Lock could not be opened!",
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.",
"Attention! Your rental has already started.\r\nIf the lock still won't open, make sure the lock is closed and end rental.\r\nImportant: Send an email to customer support (otherwise your paid rental will continue!) with: Problem description, bike number, drop-off station.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -744,21 +749,26 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error while opening lock!", "Exception message.", "OK");
viewService.DisplayAdvancedAlert(
"Lock could not be opened!",
"Please try again.",
"Exception message.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -810,19 +820,19 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -876,7 +886,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -887,16 +897,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -947,7 +957,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -958,16 +968,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1018,7 +1028,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -1029,16 +1039,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1089,7 +1099,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -1100,16 +1110,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -1161,7 +1171,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
@ -1172,16 +1182,16 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
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
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
}
}

View file

@ -42,7 +42,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -93,7 +93,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -141,11 +141,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // 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 = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -211,22 +211,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
"Can not login user mustermann@server.de. Mail address unknown or password invalid.",
"Reservation could not be canceled!",
"Your session has expired. Please login new and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -277,22 +277,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Connection error when canceling the reservation!",
"Context info\r\nIs WIFI/mobile network available and mobile data activated?",
"Reservation could not be canceled!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -343,22 +343,23 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // 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 = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
viewService.DisplayAdvancedAlert(
"Reservation could not be canceled!",
"Exception message.",
"Please try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -415,7 +416,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
@ -430,16 +431,16 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -483,18 +484,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting to lock!", "Internet must be reachable to connect to lock of reserved bike. Please establish an Internet connection!\r\nContext info.\r\nIs WIFI/mobile network available and mobile data activated?", "OK");
viewService.DisplayAlert(
"Connection to booking system not possible.",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -541,18 +546,23 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting to lock!", "Communication error during lock search.\r\nException message.", "OK");
viewService.DisplayAdvancedAlert(
"Connection to the lock could not be established.",
"Exception message.",
"Please step as close as possible to the bike lock and try again.",
"OK"
);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -601,25 +611,24 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Error when connecting to lock!",
"Lock can only be found when reserved bike is nearby.",
"Retry",
"Cancel");
"Connection to the lock could not be established.",
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -669,26 +678,26 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Error when connecting to lock!",
"Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.",
"Connection to the lock could not be established.",
"Please step as close as possible to the bike lock and try again.",
"",
"Retry",
"Cancel");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
@ -737,21 +746,21 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when connecting to lock!", "Lock status of the reserved bike could not be determined.", "OK");
viewService.DisplayAlert("Connection to the lock could not be established.", "Lock status could not be determined. Please contact customer support.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.AreEqual("Cancel reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);

View file

@ -43,7 +43,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Rad zurückgeben oder mieten", handler.ButtonText);
Assert.AreEqual("Close lock or rent bike", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Alarm/ Sounds verwalten", handler.LockitButtonText);
Assert.IsFalse(handler.IsLockitButtonVisible);
@ -78,7 +78,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open); // Requesthandler factory queries lock state to create appropriate request handler object.
@ -90,22 +90,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & end rental", subsequent.ButtonText);
Assert.AreEqual("Close lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
}
/// <summary>
@ -137,7 +137,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
connector.Command.DoBookAsync(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
@ -152,26 +152,26 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Connection error when renting the bike!",
string.Format("Attention: Lock is closed!\r\n{0}\r\n{1}", "Context info.", "Is WIFI/mobile network available and mobile data activated?"),
"Bike could not be rented!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Wiederverschließe Schloss...";
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -206,7 +206,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
connector.Command.DoBookAsync(bike).Returns(x => throw new Exception("Exception message."));
@ -221,23 +221,27 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Error when renting the bike!", "Attention: Lock is closed!\r\nException message.", "OK");
bikesViewModel.ActionText = "Wiederverschließe Schloss...";
viewService.DisplayAdvancedAlert(
"Bike could not be rented!",
"Exception message.",
"Please try again.",
"OK");
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -274,7 +278,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
@ -287,15 +291,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -339,10 +343,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(
string.Empty,
"Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?",
"Zurückgeben",
"Mieten").Returns(Task.FromResult(true));
string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => { throw new OutOfReachException(); });
@ -359,23 +360,23 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Lock can not be closed!",
"Lock cannot be closed until bike is near.\r\nPlease try again to close bike or report bike to operator!",
"Lock could not be closed!",
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -413,10 +414,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(
string.Empty,
"Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?",
"Zurückgeben",
"Mieten").Returns(Task.FromResult(true));
string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => { throw new Exception("Exception message."); });
@ -433,22 +431,22 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Lock can not be closed!",
"Please try to lock again or report bike to operator!\r\nException message.",
"Lock could not be closed!",
"Step close to the lock and try again or report bike to operator!\r\nException message.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
@ -494,7 +492,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
@ -511,18 +509,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
"Can not login user mustermann@server.de. Mail address unknown or password invalid.",
"Reservation could not be canceled!",
"Your session has expired. Please login new and try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -565,7 +563,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
@ -582,18 +580,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Connection error when canceling the reservation!",
"Context info\r\nIs WIFI/mobile network available and mobile data activated?",
"Reservation could not be canceled!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
@ -636,7 +634,7 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
@ -653,18 +651,19 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
{
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 = "<h4><b>Lock is closing.<br/>Please wait until it is completely closed.</b></h4>";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Stay with the bike until the lock is closed.";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Error when canceling the reservation!",
viewService.DisplayAdvancedAlert(
"Reservation could not be canceled!",
"Exception message.",
"Please try again.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});

View file

@ -1,14 +1,19 @@
using System;
using System.Collections.Generic;
using NSubstitute;
using NUnit.Framework;
using TestFramework.Model.Services.Geolocation;
using TestFramework.Services.BluetoothLock;
using TINK.Model.Bikes.BikeInfoNS.BikeNS;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.User;
using TINK.Services.BluetoothLock;
using TINK.Services.Geolocation;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
@ -26,6 +31,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
{
// Verify handler for disposable bike.
var bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "12"),
"My Station Name");
Assert.AreEqual(InUseStateEnum.Disposable, bike.State.Value);
@ -39,13 +49,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */ ,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for requested bike with state unknown.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id */, new Guid(), /*K User*/ null, /*K Admin*/ null, /*K Seed*/ null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
"My Station Name");
Assert.AreEqual(
@ -57,13 +72,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for requested bike with state closed.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
"My Station Name");
bike.LockInfo.State = LockingState.Closed;
@ -76,13 +96,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for requested bike with state open.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null /* user key */, null, null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
"My Station Name");
bike.LockInfo.State = LockingState.Open;
@ -95,13 +120,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for booked bike with state closed.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
"My Station Name");
bike.LockInfo.State = LockingState.Closed;
@ -114,13 +144,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for booked bike with state open.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
"My Station Name");
bike.LockInfo.State = LockingState.Open;
@ -133,13 +168,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
// Verify handler for booked bike with state unknown.
bike = new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new BikeInfo(new TINK.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new Drive(), TINK.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
"My Station Name");
@ -152,10 +192,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
Substitute.For<ISmartDevice>(),
null /* viewService */,
NSubstitute.Substitute.For<IBikesViewModel>(),
NSubstitute.Substitute.For<IUser>()).GetType());
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>()).GetType());
}
}
}

View file

@ -0,0 +1,553 @@
using System;
using System.Threading.Tasks;
using Newtonsoft.Json;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using NUnit.Framework;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Connector;
using TINK.Model.State;
using TINK.Model.User;
using TINK.Repository.Exception;
using TINK.Repository.Request;
using TINK.Repository.Response;
using TINK.Services.BluetoothLock;
using TINK.Services.Geolocation;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand;
namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock
{
[TestFixture]
public class TestReturnBikeActionViewModel
{
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks> Replaces test TestReturnOutOfReach which was removed for sharee.bike version ~3.0.362. </remarks>
[Test]
public async Task TestReturnLastGeolocatonNullLockOutOfReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Throws((x) =>
{
returnBikeActionViewModel.ReportStep(Step.StartingQueryLocation);
returnBikeActionViewModel.ReportStateAsync(State.DisconnetedNoLocationError, "").Wait();
returnBikeActionViewModel.ReportStep(Step.DisconnectingLockOnDisconnectedNoLocationError);
returnBikeActionViewModel.ReportStateAsync(State.QueryLocationSucceeded, "").Wait();
throw new Exception();
});
bike.State.Value.Returns(InUseStateEnum.Booked);
await returnBikeActionViewModel.EndRentalAsync();
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
viewService.DisplayAlert(
"Rental could not be terminated!",
"We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!\r\n\r\nApproach the bike lock, turn on Bluetooth and Location services and try again.",
"OK");
bikesViewModel.ActionText = "Disconnecting lock...";
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks>Replaces test TestReturnLockInReachNoGeolocation which was removed for sharee.bike older ~ 3.0.362.</remarks>
[Test]
public void TestReturnStartGetGeolocationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Throws((x) =>
{
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(State.QueryLocationFailed, "Ups...").Wait();
throw new Exception();
});
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
var subsequent = handler.EndRentalAsync();
// Verify behavior
Received.InOrder(async () =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "Query location...";
await viewService.DisplayAlert(
"Rental could not be terminated!",
"Grant Location permission, activate Location services and try again.",
"OK");
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
[Test]
public async Task TestReturnGetGeolocationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>())
.Returns((x) =>
{
handler.ReportStep(Step.StartingQueryLocation);
handler.ReportStateAsync(State.QueryLocationFailed, "Ups...").Wait();
return Task.FromException<LocationDto>(new Exception("Ups..."));
});
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
await handler.EndRentalAsync();
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "Query location...";
viewService.DisplayAlert(
"Rental could not be terminated!",
"Grant Location permission, activate Location services and try again.",
"OK");
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Disposable closed
/// </summary>
[Test]
public async Task TestReturnLockInReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
bike.GetLockedBikeLocationAsync(Arg.Any<IGetLockedLocationCommandListener>()).Returns((x) =>
{
returnBikeActionViewModel.ReportStep(Step.StartingQueryLocation);
returnBikeActionViewModel.ReportStateAsync(State.QueryLocationSucceeded, string.Empty).Wait();
return Task.FromResult(new LocationDto.Builder().Build());
});
bike.State.Value.Returns(InUseStateEnum.Disposable); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
await returnBikeActionViewModel.EndRentalAsync();
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Query location...";
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x != null));
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Same as initial state.
/// </summary>
[Test]
public async Task TestReturnReturnFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new WebConnectFailureException("Context info", new Exception("hoppla")));
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
await handler.EndRentalAsync();
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Rental could not be terminated!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
"OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Same as initial state.
/// </summary>
[Test]
public async Task TestReturnReturnFailsNotAtStationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
NotAtStationException.IsNotAtStation("Failure 2178: bike 1545 out of GEO fencing. 15986 meter distance to next station 42. OK: bike 1545 locked confirmed", out NotAtStationException notAtStationException);
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
throw notAtStationException);
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
await handler.EndRentalAsync();
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Rental could not be terminated!", "End rental outside or at wrong station is not possible. Distance to next suitable station 42 is 15986 m.", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Same as initial state.
/// </summary>
[Test]
public async Task TestReturnReturnFailsNoGPSDataException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
NoGPSDataException.IsNoGPSData("Failure 2245: No GPS data, state change forbidden.", out NoGPSDataException noGPSDataException);
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
throw noGPSDataException);
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
await handler.EndRentalAsync();
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert("Rental could not be terminated!", "End rental at an unknown location is not possible.\r\nRental can be ended if\r\n- location information is available when closing lock\r\n- bike is in reach and location information is available when pressing button \"End rental\"", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Same as initial state.
/// </summary>
[Test]
public async Task TestReturnReturnFailsResponseException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
throw new ReturnBikeException(JsonConvert.DeserializeObject<DoReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requesthandler factory queries lock state to create appropriate request handler object.
await handler.EndRentalAsync();
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert("Rental could not be terminated!", "Outer message.", "Some invalid data received!", "OK");
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Same as initial state.
/// </summary>
[Test]
public async Task TestReturnReturnFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
locks,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "End rental of bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
await returnBikeActionViewModel.EndRentalAsync();
await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "One moment please...";
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAlert(
"Rental could not be terminated!",
"Exception message.",
"OK"
);
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
}
}
}