sharee.bike-App/TestShareeLib/Model/Bikes/BikeInfoNS/BluetoothLock/Command/TestGetBikeLocationCommand.cs

239 lines
7.8 KiB
C#
Raw Normal View History

2023-08-31 12:20:06 +02:00
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NSubstitute.ExceptionExtensions;
using NUnit.Framework;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock;
using TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command;
using TINK.Model.Connector;
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.User;
2023-08-31 12:31:38 +02:00
using TINK.Repository.Request;
2023-08-31 12:20:06 +02:00
using TINK.Services.BluetoothLock;
using TINK.Services.Geolocation;
using static TINK.Model.Bikes.BikeInfoNS.BluetoothLock.Command.GetLockedLocationCommand;
namespace TestShareeLib.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
public class TestGetBikeLocationCommand
{
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks> Replaces test TestReturnOutOfReach which was removed for sharee.bike version ~3.0.362. </remarks>
[Test]
public void TestReturnLastGeolocatonNullLockOutOfReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Disconnected); // Simulate bike out of reach.
locks.DisconnectAsync(0, Arg.Any<Guid>()).Returns(LockingState.UnknownDisconnected); // Simulate disconnecting.
bike.State.Value.Returns(InUseStateEnum.Booked);
Assert.That(
async () => await InvokeAsync<TestGetBikeLocationCommand>(
bike,
geolocation,
locks,
listener: listener),
Throws.TypeOf<Exception>());
// Verify behavior
Received.InOrder(() =>
{
listener.ReportStep(Step.StartingQueryLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
listener.ReportStateAsync(State.DisconnetedNoLocationError, "");
listener.ReportStep(Step.DisconnectingLockOnDisconnectedNoLocationError);
locks.DisconnectAsync(0, Arg.Any<Guid>());
listener.ReportStateAsync(State.QueryLocationSucceeded, "");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
/// <remarks>Replaces test TestReturnLockInReachNoGeolocation which was removed for sharee.bike older ~ 3.0.362.</remarks>
[Test]
public void TestReturnStartGetGeolocationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Throws(new Exception("Ups...")); // Simulate error when starting query for geolocation.
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
var subsequent = InvokeAsync<TestGetBikeLocationCommand>(
bike,
geolocation,
locks,
listener: listener);
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.StartingQueryLocation);
locks[0].GetDeviceState();
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
await listener.ReportStateAsync(State.QueryLocationFailed, "Ups...");
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Booked, lock state unknown.
/// </summary>
[Test]
public void TestReturnGetGeolocationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
bike.Id.Returns("0");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromException<IGeolocation>(new Exception("Ups..."))); // Simulate error starting query for geolocation.
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking state does not change.
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
Assert.That(
async () => await InvokeAsync<TestGetBikeLocationCommand>(
bike,
geolocation,
locks,
listener: listener),
Throws.TypeOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.StartingQueryLocation);
locks[0].GetDeviceState();
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
await listener.ReportStateAsync(State.QueryLocationFailed, "Ups...");
});
}
/// <summary>
/// Use case: End rental.
/// Final state: Disposable closed
/// </summary>
[Test]
public async Task TestReturnLockInReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
bike.LockInfo.Location.Returns((IGeolocation)null);
bike.Id.Returns("0");
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach. If bike is out of reach bluetooth state changes to unknown.
var location = Substitute.For<IGeolocation>();
location.Latitude.Returns(7);
location.Longitude.Returns(9);
location.Timestamp.Returns(DateTimeOffset.MinValue);
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime>()).Returns(Task.FromResult(
location
)); ;
var lockingLocation = await InvokeAsync<TestGetBikeLocationCommand>(
bike,
geolocation,
locks,
() => DateTime.MinValue,
listener);
Assert.That(lockingLocation.Latitude, Is.EqualTo(7));
Assert.That(lockingLocation.Longitude, Is.EqualTo(9));
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.StartingQueryLocation);
var dummyLoc = bike.LockInfo.Location; // Check if location was available when closing lock.
locks[0].GetDeviceState(); // Check if bike is connected.
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime>()); // Query current location.
await listener.ReportStateAsync(State.QueryLocationSucceeded, string.Empty);
});
}
2023-08-31 12:31:38 +02:00
/// <summary>
/// Use case: End rental.
/// Final state: Disposable closed
/// </summary>
[Test]
public async Task TestReturnClosingLockLocationAvailable()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IGetLockedLocationCommandListener>();
var closingLockLocation = Substitute.For<IGeolocation>();
closingLockLocation.Latitude.Returns(7);
closingLockLocation.Longitude.Returns(9);
closingLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
bike.LockInfo.Location.Returns((IGeolocation)closingLockLocation); // When locking bike geolocation was available.
var lockingLocation = await InvokeAsync<TestGetBikeLocationCommand>(
bike,
geolocation,
locks,
() => DateTime.MinValue,
listener);
// Verify behavior
Received.InOrder(() =>
{
listener.ReportStep(Step.StartingQueryLocation);
return;
});
}
2023-08-31 12:20:06 +02:00
}
}