mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2024-11-16 07:06:33 +01:00
1340 lines
52 KiB
C#
1340 lines
52 KiB
C#
using System;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using Newtonsoft.Json;
|
|
using NSubstitute;
|
|
using NUnit.Framework;
|
|
using TINK.Model;
|
|
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
|
|
using TINK.Model.Connector;
|
|
using TINK.Model.Device;
|
|
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.BluetoothLock.Exception;
|
|
using TINK.Services.BluetoothLock.Tdo;
|
|
using TINK.Services.Geolocation;
|
|
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
|
|
{
|
|
[TestFixture]
|
|
public class TestBookedClosed
|
|
{
|
|
/// <summary>
|
|
/// Test construction of object.
|
|
/// </summary>
|
|
[Test]
|
|
public void Testctor()
|
|
{
|
|
var handler = new BookedClosed(
|
|
Substitute.For<IBikeInfoMutable>(),
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => Substitute.For<IConnector>(),
|
|
Substitute.For<IGeolocation>(),
|
|
Substitute.For<ILocksService>(),
|
|
() => Substitute.For<IPollingUpdateTaskManager>(),
|
|
Substitute.For<ISmartDevice>(),
|
|
Substitute.For<IViewService>(),
|
|
Substitute.For<IBikesViewModel>(),
|
|
Substitute.For<IUser>());
|
|
|
|
// Verify prerequisites.
|
|
//Assert.AreEqual("Return bike", handler.ButtonText);
|
|
//Assert.IsTrue(handler.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", handler.LockitButtonText);
|
|
Assert.IsTrue(handler.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Comment: User deceide 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<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(false));
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
viewService.DisplayAlert(string.Empty, "Return bike Nr. 0?", "Yes", "No");
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Final state: Disposable closed
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnOutOfReach()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return bike Nr. 0?", "Yes", "No").Returns(Task.FromResult(true));
|
|
|
|
locks[0].GetDeviceState().Returns(DeviceState.Disconnected); // Simulate bike out of reach.
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
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
|
|
bikesViewModel.ActionText = string.Empty;
|
|
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: Return bike.
|
|
/// Final state: Disposable closed
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnLockInReach()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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.
|
|
|
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime>()).Returns(Task.FromResult(
|
|
new Xamarin.Essentials.Location(7, 9)
|
|
));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
// Verify behaviour
|
|
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
|
|
bikesViewModel.ActionText = "Query location...";
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
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
|
|
bikesViewModel.ActionText = string.Empty;
|
|
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: Return bike.
|
|
/// Final state: Disposable closed
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnLockInReachNoGeolocation()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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.
|
|
|
|
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime>()).Returns<Xamarin.Essentials.Location>(x => throw new Exception());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
// Verify behaviour
|
|
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
|
|
bikesViewModel.ActionText = "Query location...";
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
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
|
|
bikesViewModel.ActionText = string.Empty;
|
|
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: Return bike.
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnReturnFailsWebConnectFailureException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = string.Empty;
|
|
viewService.DisplayAdvancedAlert(
|
|
"Connection error when returning the bike!",
|
|
"Internet must be available when returning the bike.\r\nIs WIFI available/ mobile network available and mobile data activated / ... ?",
|
|
"Context info",
|
|
"OK");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnReturnFailsNotAtStationException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = string.Empty;
|
|
viewService.DisplayAlert("Error returning bike!", "Returning bike outside of station is not possible. Distance to station 42 is 15986 m.", "OK");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnReturnFailsNoGPSDataException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = string.Empty;
|
|
viewService.DisplayAlert("Error returning bike!", "Returning bike at an unknown location is not possible.\r\nBike can be returned if\r\n- location information is available when closing lock\r\n- bike is in reach and location information is available when pressing button \"Return bike\"", "OK");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnReturnFailsResponseException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
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
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Return bike.
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestReturnReturnFailsException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
bike.Id.Returns("0");
|
|
|
|
viewService.DisplayAlert(string.Empty, "Return 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); // Reqesthandler factory queries state to create appropriate request handler object.
|
|
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
|
|
|
|
var subsequent = handler.HandleRequestOption1().Result;
|
|
|
|
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "Returning bike...";
|
|
connector.Command.DoReturn(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = string.Empty;
|
|
viewService.DisplayAlert("Error returning bike!", "Exception message.", "OK");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state after action
|
|
//Assert.AreEqual("Return bike", subsequent.ButtonText);
|
|
//Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked opened.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpen()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, null);
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // 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 & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenOpenFailsOutOfReachException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Closed);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Disconnected" after action
|
|
Assert.AreEqual(nameof(BookedDisconnected), subsequent.ButtonText);
|
|
Assert.IsFalse(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenOpenFailsCouldntOpenBoldBlockedException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldIsBlockedException());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Closed);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Unknown" after action
|
|
Assert.AreEqual("Open lock", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenOpenFailsCouldntOpenInconsistentStateExecptionClosed()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenInconsistentStateExecption(LockingState.Closed));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Closed);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // 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("Return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenOpenFailsCouldntOpenInconsistentStateExecption()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldStatusIsUnknownException());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Closed);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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. Please try again.\r\n\r\nAttention! Your rental has already started.\r\n\r\nIf the lock still won't open, make sure the lock is closed and return the bike. Please report it to the support!", "OK");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Disconnected" after action
|
|
Assert.AreEqual("Open lock", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Same as initial state.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenOpenFailsException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Closed);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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");
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Disconnected" after action
|
|
Assert.AreEqual(nameof(BookedDisconnected), subsequent.ButtonText);
|
|
Assert.IsFalse(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked opened.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenGetBatteryPercentageAsyncThrowsOutOfReachException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
|
|
|
|
locks[0].GetBatteryPercentageAsync().Returns<Task<double>>(x => throw new OutOfReachException());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Battery status can only be read when bike is nearby.";
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, null);
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Open" after action
|
|
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked opened.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenGetBatteryPercentageAsyncThrowsExcepton()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
|
|
|
|
locks[0].GetBatteryPercentageAsync().Returns<Task<double>>(x => throw new Exception());
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Battery status cannot be read.";
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, null);
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Closed" after action
|
|
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked open.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenUpdateLockingStateFailsWebConnectFailureException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(LockitLockingState.Open);
|
|
|
|
connector.Command.UpdateLockingStateAsync(bike, null).Returns(x => throw new WebConnectFailureException("Context info", new System.Exception("hoppla")));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Open);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, null);
|
|
bikesViewModel.ActionText = "No web error on updating locking status.";
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
|
|
bikesViewModel.ActionText = string.Empty;
|
|
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
|
});
|
|
|
|
// Verify state "Booked Open" after action
|
|
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked open.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenUpdateLockingStateFailsException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(LockitLockingState.Open);
|
|
|
|
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x => throw new Exception("Exception message."));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Open);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = "Connection error on updating locking status.";
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // 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 & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Use case: Open lock
|
|
/// Final state: Booked open.
|
|
/// </summary>
|
|
[Test]
|
|
public void TestOpenUpdateLockingStateFailsResponseException()
|
|
{
|
|
var bike = Substitute.For<IBikeInfoMutable>();
|
|
var connector = Substitute.For<IConnector>();
|
|
var command = Substitute.For<ICommand>();
|
|
var geolocation = Substitute.For<IGeolocation>();
|
|
var locks = Substitute.For<ILocksService>();
|
|
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
|
var viewService = Substitute.For<IViewService>();
|
|
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
|
var activeUser = Substitute.For<IUser>();
|
|
|
|
var handler = new BookedClosed(
|
|
bike,
|
|
() => true, // isConnectedDelegate
|
|
(isConnexted) => connector,
|
|
geolocation,
|
|
locks,
|
|
() => pollingManager,
|
|
Substitute.For<ISmartDevice>(),
|
|
viewService,
|
|
bikesViewModel,
|
|
activeUser);
|
|
|
|
locks[0].OpenAsync()
|
|
.Returns(LockitLockingState.Open);
|
|
|
|
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x =>
|
|
throw new ReturnBikeException(JsonConvert.DeserializeObject<DoReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
|
|
|
|
bike.State.Value.Returns(InUseStateEnum.Booked);
|
|
bike.LockInfo.State.Returns(LockingState.Open);
|
|
|
|
var subsequent = handler.HandleRequestOption2().Result;
|
|
|
|
// Verify behaviour
|
|
Received.InOrder(() =>
|
|
{
|
|
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
|
bikesViewModel.ActionText = "One moment please...";
|
|
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
|
|
bikesViewModel.ActionText = "<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...";
|
|
locks[0].GetBatteryPercentageAsync();
|
|
bikesViewModel.ActionText = "Updating lock state...";
|
|
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
|
|
bikesViewModel.ActionText = "Status error on updating lock state.";
|
|
bikesViewModel.ActionText = "Updating...";
|
|
pollingManager.StartUpdateAyncPeridically(); // 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 & return bike", subsequent.ButtonText);
|
|
Assert.IsTrue(subsequent.IsButtonVisible);
|
|
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
|
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
|
}
|
|
}
|
|
}
|