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

444 lines
16 KiB
C#
Raw Normal View History

2022-10-26 20:53:18 +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 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;
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
[TestFixture]
public class TestDisposableOpen
{
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor()
{
var handler = new DisposableOpen(
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-11-06 12:23:09 +01:00
Assert.AreEqual("Rent bike", handler.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(handler.IsButtonVisible);
2023-11-06 12:23:09 +01:00
Assert.AreEqual("Close lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Booked Open.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestDoBook()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
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
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike);
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBookAsync(bike);
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
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-11-06 12:23:09 +01:00
Assert.AreEqual("Close lock", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2023-11-06 12:23:09 +01:00
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Disposable Closed.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestDoBookDoReserveFailsWebConnectFailureException()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
connector.Command.DoReserve(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Disposable);
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
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike);
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-11-06 12:23:09 +01: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");
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
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-11-06 12:23:09 +01:00
Assert.AreEqual("Rent bike", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2023-11-06 12:23:09 +01:00
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Disposable Closed.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestDoBookDoReserveFailsException()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
connector.Command.DoReserve(bike).Returns(x => throw new Exception("Exception message."));
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Disposable);
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
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = "Reserving bike...";
connector.Command.DoReserve(bike);
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-11-06 12:23:09 +01:00
viewService.DisplayAdvancedAlert("Bike could not be reserved!", "Exception message.","Please try again.", "OK");
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
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-11-06 12:23:09 +01:00
Assert.AreEqual("Rent bike", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2023-11-06 12:23:09 +01:00
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Disposable Closed.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestCloseLock()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
var subsequent = handler.HandleRequestOption2().Result;
2022-09-06 16:08:19 +02:00
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
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
locks[0].CloseAsync();
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
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-11-06 12:23:09 +01:00
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2023-11-06 12:23:09 +01:00
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
2022-09-06 16:08:19 +02:00
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Same as initial state.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestCloseLockCloseFailsOutOfReachExcption()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
var subsequent = handler.HandleRequestOption2().Result;
2022-09-06 16:08:19 +02:00
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
2023-09-22 11:38:42 +02:00
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync();
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = string.Empty;
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 = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
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);
2023-11-06 12:23:09 +01:00
Assert.AreEqual(nameof(DisposableDisconnected), subsequent.LockitButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
2023-11-06 12:23:09 +01:00
/// Final state: Same as initial state.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-11-06 12:23:09 +01:00
public void TestCloseLockCloseFailsExcption()
2022-09-06 16:08:19 +02:00
{
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
2023-11-06 12:23:09 +01:00
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
2022-09-06 16:08:19 +02:00
2023-11-06 12:23:09 +01:00
var subsequent = handler.HandleRequestOption2().Result;
2022-09-06 16:08:19 +02:00
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
2023-09-22 11:38:42 +02:00
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync();
2023-11-06 12:23:09 +01:00
bikesViewModel.ActionText = string.Empty;
viewService.DisplayAdvancedAlert(
"Lock could not be closed!",
"Exception message.",
"Please try again.",
"OK"
);
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
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);
2023-11-06 12:23:09 +01:00
Assert.AreEqual(nameof(DisposableDisconnected), subsequent.LockitButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
}
2021-07-12 21:31:46 +02:00
}