sharee.bike-App/TestShareeLib/ViewModel/Bikes/Bike/BluetoothLock/RequestHandler/TestReservedDisconnected.cs

770 lines
29 KiB
C#
Raw Normal View History

2022-09-06 16:08:19 +02:00
using System;
2021-07-12 21:31:46 +02:00
using System.Threading.Tasks;
2022-08-30 15:42:25 +02:00
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
2021-07-12 21:31:46 +02:00
using TINK.Model.Connector;
2022-08-30 15:42:25 +02:00
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.User;
2021-07-12 21:31:46 +02:00
using TINK.Repository.Exception;
2022-08-30 15:42:25 +02:00
using TINK.Repository.Response;
2021-07-12 21:31:46 +02:00
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
2022-04-10 17:38:34 +02:00
using TINK.Services.Geolocation;
2021-07-12 21:31:46 +02:00
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
2022-09-06 16:08:19 +02:00
public class TestReservedDisconnected
{
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor()
{
var handler = new ReservedDisconnected(
Substitute.For<IBikeInfoMutable>(),
() => true, // isConnectedDelegate
(isConnexted) => Substitute.For<IConnector>(),
2023-04-05 15:02:10 +02:00
Substitute.For<IGeolocationService>(),
2022-09-06 16:08:19 +02:00
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
2023-06-06 12:00:24 +02:00
/// Comment: User decide to abort canceling (user is ased whether to really cancel)
2022-09-06 16:08:19 +02:00
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationCancel()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(false));
var subsequent = handler.HandleRequestOption1().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No");
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Disposable.
/// </summary>
[Test]
public void TestCancelReservation()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
2023-06-06 12:00:24 +02:00
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
2023-05-09 08:47:52 +02:00
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // Requesthandler factory queries lock state to create appropriate request handler object.
2022-09-06 16:08:19 +02:00
var subsequent = handler.HandleRequestOption1().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike); // Booking must be performed
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Exception is thrown.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationInvalidAuthorizationResponseException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
var l_oResponse = JsonConvert.DeserializeObject<AuthorizationResponse>(@"
2021-07-12 21:31:46 +02:00
{
""response"" : ""authorization"",
""authcookie"" : ""4da3044c8657a04ba60e2eaa753bc51a"",
""user_group"" : [ ""TINK"", ""Konrad"" ],
""response_state"" : ""OK"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}");
2022-09-06 16:08:19 +02:00
connector.Command.DoCancelReservation(bike).Returns(x => throw new InvalidAuthorizationResponseException("mustermann@server.de", l_oResponse));
2023-06-06 12:00:24 +02:00
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
2023-05-09 08:47:52 +02:00
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // Requesthandler factory queries lock state to create appropriate request handler object.
2022-09-06 16:08:19 +02:00
var subsequent = handler.HandleRequestOption1().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike); // Booking must be performed
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
viewService.DisplayAlert(
2023-08-31 12:20:06 +02:00
"Reservation could not be canceled!",
"Your session has expired. Please login new and try again.",
2022-09-06 16:08:19 +02:00
"OK");
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
connector.Command.DoCancelReservation(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("chub")));
2023-06-06 12:00:24 +02:00
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
2023-05-09 08:47:52 +02:00
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // Requesthandler factory queries lock state to create appropriate request handler object.
2022-09-06 16:08:19 +02:00
var subsequent = handler.HandleRequestOption1().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike); // Booking must be performed
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
viewService.DisplayAlert(
2023-08-31 12:20:06 +02:00
"Reservation could not be canceled!",
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
2022-09-06 16:08:19 +02:00
"OK");
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
connector.Command.DoCancelReservation(bike).Returns(x => throw new Exception("Exception message."));
2023-06-06 12:00:24 +02:00
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
2023-05-09 08:47:52 +02:00
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // Requesthandler factory queries lock state to create appropriate request handler object.
2022-09-06 16:08:19 +02:00
var subsequent = handler.HandleRequestOption1().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike); // Booking must be performed
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
viewService.DisplayAdvancedAlert(
"Reservation could not be canceled!",
2022-09-06 16:08:19 +02:00
"Exception message.",
2023-08-31 12:20:06 +02:00
"Please try again.",
2022-09-06 16:08:19 +02:00
"OK");
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: reserved closed
/// </summary>
[Test]
public void TestSearch()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build()));
locks.TimeOut.Returns(timeOuts);
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
locks[0].OpenAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking call leads to setting of state to booked.
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Renting bike...";
2022-12-27 21:08:09 +01:00
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
2022-11-25 09:55:23 +01:00
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
2022-09-06 16:08:19 +02:00
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Close lock", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2023-08-31 12:20:06 +02:00
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError);
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
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"
);
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError);
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
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"
);
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => { throw new OutOfReachException(); });
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
viewService.DisplayAlert(
2023-08-31 12:20:06 +02:00
"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");
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => throw new Exception("Execption message."));
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
viewService.DisplayAdvancedAlert(
2023-08-31 12:20:06 +02:00
"Connection to the lock could not be established.",
"Please step as close as possible to the bike lock and try again.",
2022-09-06 16:08:19 +02:00
"",
"Retry",
"Cancel");
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectNotOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
2023-04-05 15:02:10 +02:00
var geolocation = Substitute.For<IGeolocationService>();
2022-09-06 16:08:19 +02:00
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var activeUser = Substitute.For<IUser>();
var timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(new LockInfoTdo.Builder { State = null }.Build());
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
2023-04-19 12:14:14 +02:00
// Verify behavior
2022-09-06 16:08:19 +02:00
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
2023-08-31 12:20:06 +02:00
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
viewService.DisplayAlert("Connection to the lock could not be established.", "Lock status could not be determined. Please contact customer support.", "OK");
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Updating...";
2023-08-31 12:20:06 +02:00
pollingManager.StartAsync(); // polling must be restarted again
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2022-09-06 16:08:19 +02:00
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Cancel reservation", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
}
2021-07-12 21:31:46 +02:00
}