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

620 lines
23 KiB
C#
Raw Normal View History

2022-09-06 16:08:19 +02:00
using System;
2022-08-30 15:42:25 +02:00
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
2021-07-12 21:31:46 +02:00
using NSubstitute;
2022-08-30 15:42:25 +02:00
using NUnit.Framework;
using TINK.Model;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
2023-08-31 12:20:06 +02:00
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command;
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;
using TINK.Repository.Exception;
using TINK.Repository.Request;
using TINK.Repository.Response;
2021-07-12 21:31:46 +02:00
using TINK.Services.BluetoothLock;
2022-08-30 15:42:25 +02:00
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;
2023-08-31 12:20:06 +02:00
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
2021-07-12 21:31:46 +02:00
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
{
2022-09-06 16:08:19 +02:00
[TestFixture]
public class TestBookedOpen
{
/// <summary>
/// Test construction of object.
/// </summary>
[Test]
public void Testctor()
{
var handler = new BookedOpen(
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>());
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert.AreEqual("Close lock", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual(string.Empty, handler.LockitButtonText);
Assert.That(handler.IsLockitButtonVisible, Is.False);
2022-09-06 16:08:19 +02:00
}
/// <summary>
2023-08-31 12:20:06 +02:00
/// Use case: Close lock
/// Final state: Booked closed.
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-08-31 12:20:06 +02:00
public void TestClose()
2022-09-06 16:08:19 +02:00
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new BookedOpen(
bike,
() => true, // isConnectedDelegate
2023-08-31 12:20:06 +02:00
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocationService>(),
2022-09-06 16:08:19 +02:00
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
2023-08-31 12:20:06 +02:00
Substitute.For<IUser>());
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
return Task.CompletedTask;
}
);
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
2023-08-31 12:20:06 +02:00
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed)); // Return lock state indicating success
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed); // Return lock state indicating success
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-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
bikesViewModel.ActionText = "One moment please...";
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
});
2023-08-31 12:20:06 +02:00
// Verify state "Booked Closed" after action
Assert.AreEqual("End rental", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
2022-09-06 16:08:19 +02:00
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
2023-08-31 12:20:06 +02:00
/// Use case: Close lock
2022-09-06 16:08:19 +02:00
/// </summary>
[Test]
2023-08-31 12:20:06 +02:00
public void TestCloseCloseFailsOutOfReachException()
2022-09-06 16:08:19 +02:00
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new BookedOpen(
bike,
() => true, // isConnectedDelegate
2023-08-31 12:20:06 +02:00
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocationService>(),
2022-09-06 16:08:19 +02:00
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
2023-08-31 12:20:06 +02:00
Substitute.For<IUser>());
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(CloseCommand.State.OutOfReachError, "");
throw new OutOfReachException();
}
);
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
2023-08-31 12:20:06 +02:00
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#endif
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); /// If <see cref="OutOfReachException"/> is fired lock state is set to state unknown because disconnected.
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-09-22 11:38:42 +02:00
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
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");
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
});
2023-08-31 12:20:06 +02:00
// Verify state "Booked disconnected" after action
Assert.AreEqual("BookedDisconnected", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
[Test]
2023-08-31 12:20:06 +02:00
public void TestCloseCloseFailsCouldntCloseMovingException()
2022-09-06 16:08:19 +02:00
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new BookedOpen(
bike,
() => true, // isConnectedDelegate
2023-08-31 12:20:06 +02:00
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocationService>(),
2022-09-06 16:08:19 +02:00
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
2023-08-31 12:20:06 +02:00
Substitute.For<IUser>());
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(CloseCommand.State.CouldntCloseMovingError, "");
throw new CouldntCloseMovingException();
}
);
bike.LockInfo.State.Returns(LockingState.Open); // Locking state is open when CouldntCloseMovingException occurs.
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
2023-08-31 12:20:06 +02:00
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseMovingException());
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#endif
bike.State.Value.Returns(InUseStateEnum.Booked);
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-09-22 11:38:42 +02:00
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
viewService.DisplayAlert("Lock could not be closed!", "The process is motion sensitive. Step close to the lock, do not move, 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
});
2023-08-31 12:20:06 +02:00
// Verify state after action
Assert.AreEqual("Close lock", subsequent.ButtonText);
2022-10-03 17:55:10 +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
}
[Test]
2023-08-31 12:20:06 +02:00
public void TestCloseCloseFailsCouldntCloseBoltBlockedException()
2022-09-06 16:08:19 +02:00
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
var viewService = Substitute.For<IViewService>();
var bikesViewModel = Substitute.For<IBikesViewModel>();
var handler = new BookedOpen(
bike,
() => true, // isConnectedDelegate
2023-08-31 12:20:06 +02:00
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocationService>(),
2022-09-06 16:08:19 +02:00
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
2023-08-31 12:20:06 +02:00
Substitute.For<IUser>());
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(CloseCommand.State.CouldntCloseBoltBlockedError, "");
throw new CouldntCloseBoltBlockedException();
}
);
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError); // Locking state is unknown when CouldntCloseBoltBlockedException occurs.
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
2023-08-31 12:20:06 +02:00
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseBoltBlockedException());
2022-09-06 16:08:19 +02:00
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
2023-08-31 12:20:06 +02:00
var subsequent = handler.HandleRequestOption1().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.";
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
viewService.DisplayAlert("Lock could not be closed!", "Lock bolt is blocked. Make sure that no spoke or any other obstacle prevents the lock from closing 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 "Booked disconnected" after action
2023-08-31 12:20:06 +02:00
Assert.AreEqual("Open lock", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
2022-09-06 16:08:19 +02:00
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseCloseFailsException()
{
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 BookedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
await handler.ReportStateAsync(CloseCommand.State.GeneralCloseError, "Exception message.");
throw new Exception("Exception message.");
}
);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // If CloseLock fires an exception of type Exception lock state is set to unknown.
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
2023-08-31 12:20:06 +02:00
var subsequent = handler.HandleRequestOption1().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.";
2023-08-31 12:20:06 +02:00
#if USELOCALINSTANCE
2022-09-06 16:08:19 +02:00
locks.Received()[0].CloseAsync(); // Lock must be closed
2023-08-31 12:20:06 +02:00
#endif
2023-02-22 14:03:35 +01:00
bikesViewModel.ActionText = string.Empty;
2023-08-31 12:20:06 +02:00
viewService.DisplayAlert(
"Lock could not be closed!",
"Exception message.",
"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 "Booked Disconnected" after action
Assert.AreEqual("BookedDisconnected", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsWebConnectFailureException()
{
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 BookedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>()).Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.WebConnectFailed, "Context info");
}
);
bike.LockInfo.State.Returns(LockingState.Closed);
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
.Returns(LockitLockingState.Closed); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x => throw new WebConnectFailureException("Context info", new System.Exception("hoppla")));
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
2023-08-31 12:20:06 +02:00
var subsequent = handler.HandleRequestOption1().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.";
2023-08-31 12:20:06 +02:00
#if USELOCALINSTANCE
2022-09-06 16:08:19 +02:00
locks.Received()[0].CloseAsync(); // Lock must be closed
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
2023-08-31 12:20:06 +02:00
#endif
2023-04-05 15:02:10 +02:00
bikesViewModel.ActionText = "Internet must be available for updating lock status. Please establish an Internet connection!";
2023-08-31 12:20:06 +02:00
bikesViewModel.ActionText = "One moment please...";
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 "Booked Closed" after action
2023-04-05 15:02:10 +02:00
Assert.AreEqual("End rental", subsequent.ButtonText);
2022-10-03 17:55:10 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2022-09-06 16:08:19 +02:00
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsException()
{
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 BookedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.BackendUpdateFailed, "Exception message.");
}
);
bike.LockInfo.State.Returns(LockingState.Closed);
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
.Returns(LockitLockingState.Closed); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x => throw new Exception("Exception message."));
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
2023-08-31 12:20:06 +02:00
var subsequent = handler.HandleRequestOption1().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.";
2023-08-31 12:20:06 +02:00
#if USELOCALINSTANCE
2022-09-06 16:08:19 +02:00
locks.Received()[0].CloseAsync(); // Lock must be closed
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Connection error on updating locking status.";
2023-08-31 12:20:06 +02:00
bikesViewModel.ActionText = "One moment please...";
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 "Booked Closed" after action
2023-04-05 15:02:10 +02:00
Assert.AreEqual("End rental", subsequent.ButtonText);
2022-10-03 17:55:10 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2022-09-06 16:08:19 +02:00
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: close lock
/// Final state: Booked closed.
/// </summary>
[Test]
public void TestCloseUpdateLockingStateFailsResponseException()
{
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 BookedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
2023-08-31 12:20:06 +02:00
#if !USELOCALINSTANCE
bike.CloseLockAsync(Arg.Any<ICloseCommandListener>(), Arg.Any<Task>())
.Returns(async x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
handler.ReportStep(Step.ClosingLock);
handler.ReportStep(Step.UpdateLockingState);
await handler.ReportStateAsync(CloseCommand.State.ResponseIsInvalid, "Some invalid data received");
}
);
bike.LockInfo.State.Returns(LockingState.Closed);
#else
2022-09-06 16:08:19 +02:00
locks[0].CloseAsync()
.Returns(LockitLockingState.Closed); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x =>
throw new ReturnBikeException(JsonConvert.DeserializeObject<DoReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bike.State.Value.Returns(InUseStateEnum.Booked);
2023-08-31 12:20:06 +02:00
var subsequent = handler.HandleRequestOption1().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.";
2023-08-31 12:20:06 +02:00
#if USELOCALINSTANCE
2022-09-06 16:08:19 +02:00
locks.Received()[0].CloseAsync(); // Lock must be closed
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
2023-08-31 12:20:06 +02:00
#endif
2022-09-06 16:08:19 +02:00
bikesViewModel.ActionText = "Status error on updating lock state.";
2023-08-31 12:20:06 +02:00
bikesViewModel.ActionText = "One moment please...";
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 "Booked Closed" after action
2023-04-05 15:02:10 +02:00
Assert.AreEqual("End rental", subsequent.ButtonText);
2022-10-03 17:55:10 +02:00
Assert.IsTrue(subsequent.IsButtonVisible);
2022-09-06 16:08:19 +02:00
Assert.AreEqual("Open lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
}
2021-07-12 21:31:46 +02:00
}