using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Connector;
using ShareeBike.Model.State;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.View;
using ShareeBike.ViewModel;
using ShareeBike.ViewModel.Bikes;
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock;
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock
{
[TestFixture]
public class TestCloseLockActionViewModel
{
///
/// Use case: Close lock.
/// Final state: Occupied closed, End rental requested
///
[Test]
public async Task TestCloseLockAndRequestEndRental()
{
var bike = Substitute.For();
var connector = Substitute.For();
var command = Substitute.For();
var locks = Substitute.For();
var pollingManager = Substitute.For();
var viewService = Substitute.For();
var bikesViewModel = Substitute.For();
var listener = Substitute.For();
var closeLockActionViewModel = new CloseLockActionViewModel(
bike,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
bike.CloseLockAsync(Arg.Any(), Arg.Any()).Returns(x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
closeLockActionViewModel.ReportStep(CloseCommand.Step.StartingQueryingLocation);
closeLockActionViewModel.ReportStep(CloseCommand.Step.ClosingLock);
closeLockActionViewModel.ReportStep(CloseCommand.Step.WaitStopPollingQueryLocation);
closeLockActionViewModel.ReportStep(CloseCommand.Step.QueryLocationTerminated);
closeLockActionViewModel.ReportStep(CloseCommand.Step.UpdateLockingState);
return Task.CompletedTask;
});
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
await closeLockActionViewModel.CloseLockAsync();
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.StartRentalProcess(Arg.Is(
x => x.BikeId == "0"
&& x.State == CurrentRentalProcess.CloseLock
&& x.StepIndex == 1
&& x.Result == CurrentStepStatus.None));
//Step.StartingQueryingLocation
bikesViewModel.ActionText = "Start query location...";
//Step.ClosingLock
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
//Step.WaitStopPollingQueryLocation
bikesViewModel.ActionText = "Query location...";
//Step.UpdateLockingState
bikesViewModel.ActionText = "Updating lock state...";
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
bikesViewModel.RentalProcess.StepIndex = 2;
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
//Ask whether park bike or end rental
viewService.DisplayAlert(
"Please choose",
"Do you want to park the bike to continue riding later or return the bike now and end the rental?",
"End rental",
"Park bike"
);
closeLockActionViewModel.IsEndRentalRequested = true;
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
bikesViewModel.ActionText = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
return;
});
}
///
/// Use case: Close lock.
/// Final state: Occupied closed, Park bike requested
///
[Test]
public async Task TestCloseLockAndRequestParkBike()
{
var bike = Substitute.For();
var connector = Substitute.For();
var command = Substitute.For();
var locks = Substitute.For();
var pollingManager = Substitute.For();
var viewService = Substitute.For();
var bikesViewModel = Substitute.For();
var listener = Substitute.For();
var closeLockActionViewModel = new CloseLockActionViewModel(
bike,
() => pollingManager,
viewService,
bikesViewModel);
bike.Id.Returns("0");
bike.CloseLockAsync(Arg.Any(), Arg.Any()).Returns(x =>
{
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
closeLockActionViewModel.ReportStep(CloseCommand.Step.StartingQueryingLocation);
closeLockActionViewModel.ReportStep(CloseCommand.Step.ClosingLock);
closeLockActionViewModel.ReportStep(CloseCommand.Step.WaitStopPollingQueryLocation);
closeLockActionViewModel.ReportStep(CloseCommand.Step.QueryLocationTerminated);
closeLockActionViewModel.ReportStep(CloseCommand.Step.UpdateLockingState);
return Task.CompletedTask;
});
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
await closeLockActionViewModel.CloseLockAsync();
// Verify behavior
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.StartRentalProcess(Arg.Is(
x => x.BikeId == "0"
&& x.State == CurrentRentalProcess.CloseLock
&& x.StepIndex == 1
&& x.Result == CurrentStepStatus.None));
//Step.StartingQueryingLocation
bikesViewModel.ActionText = "Start query location...";
//Step.ClosingLock
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
//Step.WaitStopPollingQueryLocation
bikesViewModel.ActionText = "Query location...";
//Step.UpdateLockingState
bikesViewModel.ActionText = "Updating lock state...";
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
bikesViewModel.RentalProcess.StepIndex = 2;
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
//Ask whether park bike or end rental
viewService.DisplayAlert(
"Please choose",
"Do you want to park the bike to continue riding later or return the bike now and end the rental?",
"End rental",
"Park bike"
);
closeLockActionViewModel.IsEndRentalRequested = false;
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
//Show confirmation
viewService.DisplayAlert(
"Lock is closed",
"Bike is parked. Your chargeable rental continues!",
"OK"
);
bikesViewModel.ActionText = "One moment please...";
pollingManager.StartAsync(); // polling must be restarted again
bikesViewModel.ActionText = string.Empty;
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
return;
});
}
}
}