Version 3.0.381

This commit is contained in:
Anja 2024-04-09 12:53:23 +02:00
parent f963c0a219
commit 3a363acf3a
1525 changed files with 60589 additions and 125098 deletions

View file

@ -0,0 +1,58 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
using ShareeBike.Model.State;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BC
{
[TestFixture]
public class TestBikeInfo
{
/// <summary>
/// Dummy subclass to provide assess to protected member for testing.
/// </summary>
private class TestBikeInfoSubClass : BikeInfo
{
public TestBikeInfoSubClass(
IStateInfo stateInfo,
ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike bike,
DriveMutable drive,
bool? isDemo = DEFAULTVALUEISDEMO,
IEnumerable<string> group = null,
string stationId = null,
Uri operatorUri = null,
RentalDescription tariffDescription = null) : base(
stateInfo,
bike,
drive,
DataSource.Copri,
isDemo,
group,
stationId,
operatorUri,
tariffDescription)
{
}
}
[Test]
public void TestCtorBikeNull()
{
Assert.That(
() => new TestBikeInfoSubClass(new StateInfo(), null, new DriveMutable()),
Throws.ArgumentNullException);
}
[Test]
public void TestCtorDriveNull()
{
Assert.That(
() => new TestBikeInfoSubClass(new StateInfo(), new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike(string.Empty, LockModel.ILockIt), null),
Throws.ArgumentNullException);
}
}
}

View file

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.State;
using IBikeInfo = ShareeBike.Model.Bikes.BikeInfoNS.BC.IBikeInfo;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike
{
[TestFixture]
public class TestBikeInfoMutable
{
private class BikeInfoMutable : ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable
{
public BikeInfoMutable(
string id,
LockModel lockModel,
bool isDemo = false,
IEnumerable<string> group = null,
WheelType? wheelType = null,
TypeOfBike? typeOfBike = null,
AaRideType? aaRideType = null,
string description = null,
string stationId = null,
string stationName = null,
Uri operatorUri = null,
RentalDescription tariffDescription = null,
Func<DateTime> dateTimeProvider = null,
IStateInfo stateInfo = null) : base(
new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike(id, lockModel, wheelType, typeOfBike, aaRideType, description),
new ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
isDemo,
group,
stationId,
stationName,
operatorUri,
tariffDescription,
dateTimeProvider,
stateInfo)
{
}
}
[Test]
public void TestConstruct()
{
var l_oBikeInfo = new BikeInfoMutable("17", LockModel.ILockIt);
Assert.That(l_oBikeInfo.Id, Is.EqualTo("17"));
Assert.That(l_oBikeInfo.StationId, Is.Null);
Assert.That(l_oBikeInfo.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
Assert.That(l_oBikeInfo.WheelType, Is.EqualTo(null));
Assert.That(l_oBikeInfo.TypeOfBike, Is.EqualTo(null));
l_oBikeInfo = new BikeInfoMutable("22", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Cargo, AaRideType.NoAaRide, "Test description", "23");
Assert.That(l_oBikeInfo.Id, Is.EqualTo("22"));
Assert.That(l_oBikeInfo.IsDemo, Is.False);
Assert.That(l_oBikeInfo.StationId, Is.EqualTo("23"));
Assert.That(l_oBikeInfo.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
Assert.That(l_oBikeInfo.WheelType, Is.EqualTo(WheelType.Trike));
Assert.That(l_oBikeInfo.TypeOfBike, Is.EqualTo(TypeOfBike.Cargo));
}
}
}

View file

@ -0,0 +1,95 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.State;
namespace SharedBusinessLogic.Tests
{
[TestFixture]
class TestBikeMutable
{
private class BikeInfoMutable : ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable
{
public BikeInfoMutable(
string id,
LockModel lockType,
bool isDemo = false,
IEnumerable<string> group = null,
WheelType? wheelType = null,
TypeOfBike? typeOfBike = null,
AaRideType? aaRideType = null,
string description = null,
string stationId = null,
string stationName = null,
Uri operatorUri = null,
RentalDescription tariffDescription = null,
Func<DateTime> dateTimeProvider = null,
IStateInfo stateInfo = null) : base(
new Bike(id, lockType, wheelType, typeOfBike, aaRideType, description),
new ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
isDemo,
group,
stationId,
stationName,
operatorUri,
tariffDescription,
dateTimeProvider,
stateInfo)
{
}
}
[Test]
public void TestConstruct()
{
var l_oBike = new BikeInfoMutable(
"42",
LockModel.ILockIt,
false,
new List<string> { "ShareeBike" },
WheelType.Two,
TypeOfBike.Cargo);
Assert.That(l_oBike.Id, Is.EqualTo("42"));
Assert.That(l_oBike.IsDemo, Is.False);
Assert.That(l_oBike.WheelType, Is.EqualTo(WheelType.Two));
Assert.That(l_oBike.TypeOfBike, Is.EqualTo(TypeOfBike.Cargo));
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
Assert.That(l_oBike.StationId, Is.Null);
l_oBike = new BikeInfoMutable(
"17",
LockModel.ILockIt,
true,
new List<string> { "ShareeBike" },
WheelType.Mono,
TypeOfBike.Allround,
AaRideType.NoAaRide,
"Test description",
"1");
Assert.That(l_oBike.Id, Is.EqualTo("17"));
Assert.That(l_oBike.IsDemo, Is.True);
Assert.That(l_oBike.WheelType, Is.EqualTo(WheelType.Mono));
Assert.That(l_oBike.TypeOfBike, Is.EqualTo(TypeOfBike.Allround));
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
Assert.That(l_oBike.StationId, Is.EqualTo("1"));
}
[Test]
public void TestToString()
{
var l_oBike = new BikeInfoMutable("3", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo, dateTimeProvider: () => new DateTime(1970, 1, 1));
Assert.That(
l_oBike.ToString(), Is.EqualTo("Id=3, wheel(s)=Two, type=Cargo, demo=False, state=Disposable, location=On the road."));
l_oBike = new BikeInfoMutable("3", LockModel.ILockIt, true, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Allround, AaRideType.NoAaRide, "Test description", "5", dateTimeProvider: () => new DateTime(1970, 1, 1));
Assert.That(
l_oBike.ToString(), Is.EqualTo("Id=3, wheel(s)=Trike, type=Allround, demo=True, state=Disposable, location=Station 5."));
}
}
}

View file

@ -0,0 +1,59 @@
using Newtonsoft.Json;
using NUnit.Framework;
using System;
using System.Collections.Generic;
using ShareeBike.Model.Bike;
using ShareeBike.Model.State;
using BikeInfoMutable = ShareeBike.Model.Bike.BC.BikeInfoMutable;
namespace SharedBusinessLogic.Tests
{
/// <summary>
/// Exclude from build beause serialization... see below.
/// </summary>
[TestFixture]
public class TestBikeSerializeJSON
{
[Test, Ignore("Disabled because serialization does no more work due to inheritance since commit ec14b93b.")]
public void TestConstruct_SerializeJSON_Disposable()
{
// Create object to test.
var l_oBikeSource = new BikeInfoMutable(3, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo, p_oDateTimeProvider: () => new DateTime(1970, 1, 1));
// Verify prerequisites
Assert.AreEqual(InUseStateEnum.Disposable, l_oBikeSource.State.Value);
Assert.IsNull(l_oBikeSource.State.MailAddress);
Assert.IsNull(l_oBikeSource.State.Code);
Assert.IsNull(l_oBikeSource.State.From);
// Serialize object and verify.
var l_oDetected = JsonConvert.SerializeObject(l_oBikeSource, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
const string EXPECTED = @"
{
""Id"": 3,
""CurrentStation"": null,
""WheelType"": 1,
""TypeOfBike"": 1,
""State"": {
""StateInfoObject"": {
""$type"": ""ShareeBike.Model.State.StateAvailableInfo, SharedBusinessLogic""
}
}
}";
Assert.AreEqual(
TestHelper.PrepareXmlForStringCompare(EXPECTED),
TestHelper.PrepareXmlForStringCompare(l_oDetected));
// Deserialize object.
var l_oBikeTarget = JsonConvert.DeserializeObject<BikeInfoMutable>(l_oDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
// Verify state.
Assert.AreEqual(InUseStateEnum.Disposable, l_oBikeTarget.State.Value);
Assert.IsNull(l_oBikeTarget.State.MailAddress);
Assert.IsNull(l_oBikeTarget.State.Code);
Assert.IsNull(l_oBikeTarget.State.From);
}
}
}

View file

@ -0,0 +1,166 @@
using System;
using System.Collections.Generic;
using NUnit.Framework;
using SharedBusinessLogic.Tests.Framework.Model.User.Account;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.State;
using ShareeBike.Model.User;
using ShareeBike.Model.User.Account;
using ShareeBike.Repository;
using ShareeBike.ViewModel.Bikes.Bike;
using static ShareeBike.Repository.CopriCallsMemory;
namespace UITest.Fixtures.ViewModel
{
public class TestBikeViewModel
{
private class BikeInfoMutable : ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable
{
public BikeInfoMutable(
string id,
LockModel lockModel,
bool pisDemo = false,
IEnumerable<string> group = null,
WheelType? wheelType = null,
TypeOfBike? typeOfBike = null,
AaRideType? aaRideType = null,
string description = null,
string stationId = null,
string stationName = null,
Uri operatorUri = null,
Func<DateTime> dateTimeProvider = null,
IStateInfo stateInfo = null) : base(
new Bike(id, lockModel, wheelType, typeOfBike, aaRideType, description),
new ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
pisDemo,
group,
stationId,
stationName,
operatorUri,
null,
dateTimeProvider,
stateInfo)
{
}
}
/// <summary>
/// Tests base class functionality by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_Reserved(Func<ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable(
"2",
LockModel.ILockIt,
false,
new List<string> { "ShareeBike" },
WheelType.Trike,
TypeOfBike.Cargo,
AaRideType.NoAaRide,
"Test description",
"3",
"Radstation",
null,
() => new DateTime(1980, 1, 1)); // Now time stamp
// Update state from Copri.
l_oBike.State.Load(
InUseStateEnum.Reserved, // Copri acknowledges state reserved.
new DateTime(1980, 1, 1), // Date when bike was booked.
TimeSpan.FromMinutes(15),
"ragu@gnu-systems.de"); // Owner from Copri.
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, false, "987654321" /* session cookie */, new List<string> { "ShareeBike" }));
var l_oUser = new User(
l_oStoreMock,
l_oStoreMock.Load().Result,
"123456789");
// Verify prerequisites
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Reserved));
Assert.That(l_oUser.IsLoggedIn, Is.True);
Assert.That(l_oUser.Mail, Is.EqualTo(l_oBike.State.MailAddress));
// Do not update from Copri
var l_oViewModel = p_oFactory(l_oBike, l_oUser);
return l_oViewModel;
}
/// <summary>
/// Tests base class functionality by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_ReservedWithCopriConnect(Func<ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable(
"2",
LockModel.ILockIt,
false,
new List<string> { "ShareeBike" },
WheelType.Trike,
TypeOfBike.Cargo,
AaRideType.NoAaRide,
"Test description",
"3",
"Radstation",
null,
() => (new DateTime(1980, 1, 1)).Add(new TimeSpan(0, 8, 0)));
// Update state from Copri.
l_oBike.State.Load(
InUseStateEnum.Reserved, // Copri acknowledges state reserved.
new DateTime(1980, 1, 1),
TimeSpan.FromMinutes(15),
"ragu@gnu-systems.de", // Owner from Copri.
"4asdfA"); // Reservation code from Copri
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, false, "987654321" /* session cookie */, new List<string> { "ShareeBike" }));
var l_oUser = new User(
l_oStoreMock, // Mocks account store functionality.
l_oStoreMock.Load().Result,
"123456789");
// Verify prerequisites
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Reserved));
Assert.That(l_oUser.IsLoggedIn, Is.True);
Assert.That(l_oUser.Mail, Is.EqualTo(l_oBike.State.MailAddress));
var l_oViewModel = p_oFactory(l_oBike, l_oUser); // Bikes collection mock.
return l_oViewModel;
}
/// <summary>
/// Tests base class functionality by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_Booked(Func<ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable("2", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo, AaRideType.NoAaRide, "Test description", "3");
// Update from Copri.
l_oBike.State.Load(
InUseStateEnum.Booked,
new DateTime(2017, 10, 24, 21, 49, 3),
TimeSpan.FromMinutes(15),
"ragu@gnu-systems.de",
"4asdfA");
var l_oCopriServer = new CopriCallsMemory("MyMerchId", SampleSets.Set1, 1);
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, false, "987654321" /* session cookie */, new List<string> { "ShareeBike" }));
var l_oUser = new User(
l_oStoreMock,
l_oStoreMock.Load().Result,
"123456789"); // Device id
// Verify prerequisites
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
Assert.That(l_oUser.IsLoggedIn, Is.True);
Assert.That(l_oUser.Mail, Is.EqualTo(l_oBike.State.MailAddress));
var l_oViewModel = p_oFactory(l_oBike, l_oUser);
return l_oViewModel;
}
}
}

View file

@ -0,0 +1,108 @@
using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Connector;
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.AuthCommand;
using ShareeBike.Repository.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
{
[TestFixture]
public class TestAuthCommand
{
/// <summary>
/// Use case: Authenticate.
/// Final state: Authentication successfully
/// </summary>
[Test]
public async Task TestAuth()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IAuthCommandListener>();
await InvokeAsync<TestAuthCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
await connector.Command.CalculateAuthKeys(Arg.Any<IBikeInfoMutable>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.Authenticate);
await connector.Command.CalculateAuthKeys(bike);
});
}
/// <summary>
/// Use case: Authenticate.
/// Final state: Authentication failed
/// </summary>
[Test]
public void TestAuthNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IAuthCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.CalculateAuthKeys(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestAuthCommand>(
bike,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.Authenticate);
await connector.Command.CalculateAuthKeys(bike);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
/// <summary>
/// Use case: Authenticate.
/// Final state: Authentication failed
/// </summary>
[Test]
public void TestAuthGeneralException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IAuthCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.CalculateAuthKeys(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new Exception("Context info."));
Assert.That(
async () => await InvokeAsync<TestAuthCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.Authenticate);
await connector.Command.CalculateAuthKeys(bike);
await listener.ReportStateAsync(State.GeneralAuthError, "Context info.");
});
}
}
}

View file

@ -0,0 +1,139 @@
using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Connector;
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.CancelReservationCommand;
using ShareeBike.Repository.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
{
[TestFixture]
public class TestCancelReservationCommand
{
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Reservation canceled successfully
/// </summary>
[Test]
public async Task TestCancelReservation()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<ICancelReservationCommandListener>();
await InvokeAsync<TestCancelReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
await connector.Command.DoCancelReservation(Arg.Any<IBikeInfoMutable>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.CancelReservation);
await connector.Command.DoCancelReservation(bike);
});
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestCancelReservationNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<ICancelReservationCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.DoCancelReservation(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestCancelReservationCommand>(
bike,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.CancelReservation);
await connector.Command.DoCancelReservation(bike);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestCancelReservationGeneralException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<ICancelReservationCommandListener>();
connector.Command.DoCancelReservation(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new Exception("Context info."));
Assert.That(
async () => await InvokeAsync<TestCancelReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.CancelReservation);
await connector.Command.DoCancelReservation(bike);
await listener.ReportStateAsync(State.GeneralCancelReservationError, "Context info.");
});
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestCancelReservationTooManyBikesException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<ICancelReservationCommandListener>();
bike.Id.Returns("1543");
connector.Command.DoCancelReservation(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new InvalidAuthorizationResponseException("mail", new ShareeBike.Repository.Response.ResponseBase()));
Assert.That(
async () => await InvokeAsync<TestCancelReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<InvalidAuthorizationResponseException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.CancelReservation);
await connector.Command.DoCancelReservation(bike);
await listener.ReportStateAsync(State.InvalidResponse, "Your session has expired. Please login new and try again.");
});
}
}
}

View file

@ -0,0 +1,469 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.Geolocation;
using ShareeBike.Repository.Request;
using ShareeBike.Model.Connector;
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.EndRentalCommand;
using ShareeBike.Model;
using ShareeBike.Repository.Exception;
using ShareeBike.Model.State;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
{
[TestFixture]
public class TestEndRentalCommand
{
/// <summary>
/// Use case: End rental.
/// Final state: Rental ended successfully
/// </summary>
[Test]
[Ignore("bike.State.Value should be FeedbackPending")]
public async Task TestReturnClosingLockLocationAvailable()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
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 endRentalLocation = closingLockLocation;
var bookingFinished = connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
});
Assert.That(bookingFinished, Is.Not.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.FeedbackPending));
}
// <summary>
// Use case: End rental.
// Final state: Rental ended successfully
// </summary>
[Test]
[Ignore("bike.State.Value should be FeedbackPending")]
public async Task TestReturnLastGeolocationNullLockInReach()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.Location.Returns((IGeolocation)null); // Simulate that when locking bike geolocation was not available
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
newLockLocation.Latitude.Returns(7);
newLockLocation.Longitude.Returns(9);
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
var bookingFinished = connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
});
Assert.That(bookingFinished, Is.Not.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.FeedbackPending));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
public async Task TestReturnLastGeolocatonNullLockOutOfReachNoGPSDataDoNotReturn()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Disconnected); // Simulate bike not in reach.
await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
var task = connector.Command.DidNotReceive().DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
await listener.ReportStateAsync(State.NoGPSData, "There is no geolocation information available since lock is not connected");
});
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
public void TestReturnLastGeolocatonNullLockInReachGetGeolocationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
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<IGeolocation>>(x => throw new Exception("Ups...")); // Simulate error query for geolocation.
Assert.That(
async () => await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
connector.Command.DidNotReceive().DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
await listener.ReportStateAsync(State.GeneralQueryLocationFailed, "Ups...");
});
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
[Ignore("bookingFinished should be null")]
public void TestReturnLastGeolocatonNullReturnException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
newLockLocation.Latitude.Returns(7);
newLockLocation.Longitude.Returns(9);
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
throw new Exception("Ups..."));
Assert.That(
async () => await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
await listener.ReportStateAsync(State.GeneralEndRentalError, "Ups...");
});
Assert.That(bookingFinished, Is.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
[Ignore("bookingFinished should be null")]
public void TestReturnReturnNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
newLockLocation.Latitude.Returns(7);
newLockLocation.Longitude.Returns(9);
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
Assert.That(bookingFinished, Is.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
[Ignore("Exception needs to be initialized correctly. bookingFinished should be null")]
public void TestReturnNotAtStationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.Id.Returns("1545");
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
var newLockLocation = Substitute.For<IGeolocation>(); // Get geolocation from end rental
newLockLocation.Latitude.Returns(7);
newLockLocation.Longitude.Returns(9);
newLockLocation.Timestamp.Returns(DateTimeOffset.MinValue);
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns(Task.FromResult(newLockLocation));
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);
notAtStationException.Distance.Returns(15986);
notAtStationException.StationNr.Returns("42");
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x
=> throw notAtStationException);
Assert.That(
async () => await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<NotAtStationException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, Arg.Is<LocationDto>(x => x.Latitude == 7 && x.Longitude == 9));
await listener.ReportStateAsync(State.NotAtStation, "End rental outside or at unsuitable station is not possible. Distance to next suitable station 42 is 15986 m.\r\n\r\nNote: Your GPS data may not be up to date. So if you are at a suitable station, please simply try again so that your location is queried again.");
});
Assert.That(bookingFinished, Is.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
/// <summary>
/// Use case: End rental.
/// Final state: Still rented.
/// </summary>
[Test]
[Ignore("Exception needs to be initialized correctly. bookingFinished should be null")]
public void TestReturnNoGPSDataException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
static DateTime dateTime() => DateTime.MinValue;
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IEndRentalCommandListener>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.Location.Returns((IGeolocation)null); // When locking bike geolocation was not available.
locks[0].GetDeviceState().Returns(DeviceState.Connected); // Simulate bike in reach.
var endRentalLocation = geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>())
.Returns((IGeolocation)null);
NoGPSDataException.IsNoGPSData("Failure 2245: No GPS data, state change forbidden.", out NoGPSDataException noGPSDataException);
var bookingFinished = connector.Command.DoReturn(Arg.Any<IBikeInfoMutable>(), Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x =>
throw noGPSDataException);
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
Assert.That(
async () => await InvokeAsync<TestEndRentalCommand>(
bike,
geolocation,
locks,
dateTime,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<NoGPSDataException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.GetLocation);
var location = bike.LockInfo.Location;
locks[0].GetDeviceState();
var endRentalLocation = await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.ReportStep(Step.ReturnBike);
var bookingFinished = await connector.Command.DoReturn(bike, null);
await listener.ReportStateAsync(State.NoGPSData, "Failure 2245: No GPS data, state change forbidden.");
});
Assert.That(bookingFinished, Is.Null);
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
}
}

View file

@ -0,0 +1,205 @@
using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Connector;
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
using ShareeBike.Repository.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
{
[TestFixture]
public class TestStartRentalCommand
{
/// <summary>
/// Use case: Start rental.
/// Final state: Rental started successfully
/// </summary>
[Test]
public async Task TestLockClosedStartRental()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
await InvokeAsync<TestStartRentalCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
await connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>(), LockingAction.Open);
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike, LockingAction.Open);
});
}
/// <summary>
/// Use case: Start rental.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestLockClosedStartRentalNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>(), LockingAction.Open).Returns(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestStartRentalCommand>(
bike,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike, LockingAction.Open);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
/// <summary>
/// Use case: Start rental.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestLockClosedStartRentalGeneralException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>(), LockingAction.Open).Returns(x
=> throw new Exception("Context info."));
Assert.That(
async () => await InvokeAsync<TestStartRentalCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike, LockingAction.Open);
await listener.ReportStateAsync(State.GeneralStartRentalError, "Context info.");
});
}
/// <summary>
/// Use case: Start rental.
/// Final state: Rental started successfully
/// </summary>
[Test]
public async Task TestLockOpenStartRental()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Open);
await InvokeAsync<TestStartRentalCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
await connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike);
});
}
/// <summary>
/// Use case: Start rental.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestLockOpenStartRentalNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Open);
connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestStartRentalCommand>(
bike,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
/// <summary>
/// Use case: Start rental.
/// Final state: Still reserved.
/// </summary>
[Test]
public void TestLockOpenStartRentalGeneralException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartRentalCommandListener>();
bike.LockInfo.State.Returns(LockingState.Open);
connector.Command.DoBookAsync(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new Exception("Context info."));
Assert.That(
async () => await InvokeAsync<TestStartRentalCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.RentBike);
await connector.Command.DoBookAsync(bike);
await listener.ReportStateAsync(State.GeneralStartRentalError, "Context info.");
});
}
}
}

View file

@ -0,0 +1,148 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.Geolocation;
using ShareeBike.Repository.Request;
using ShareeBike.Model.Connector;
using static ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartReservationCommand;
using ShareeBike.Model;
using ShareeBike.Repository.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BikeNS.Command
{
[TestFixture]
public class TestStartReservationCommand
{
/// <summary>
/// Use case: Start reservation.
/// Final state: Reservation started successfully
/// </summary>
[Test]
public async Task TestStartReservation()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartReservationCommandListener>();
await InvokeAsync<TestStartReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener);
await connector.Command.DoReserve(Arg.Any<IBikeInfoMutable>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.ReserveBike);
await connector.Command.DoReserve(bike);
});
}
/// <summary>
/// Use case: Start reservation.
/// Final state: Reservation failed.
/// </summary>
[Test]
public void TestStartReservationNoWebException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartReservationCommandListener>();
bike.LockInfo.State.Returns(LockingState.Closed);
connector.Command.DoReserve(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
Assert.That(
async () => await InvokeAsync<TestStartReservationCommand>(
bike,
() => false, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<WebConnectFailureException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.ReserveBike);
await connector.Command.DoReserve(bike);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
/// <summary>
/// Use case: Start reservation.
/// Final state: Reservation failed.
/// </summary>
[Test]
public void TestStartReservationGeneralException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartReservationCommandListener>();
connector.Command.DoReserve(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw new Exception("Context info."));
Assert.That(
async () => await InvokeAsync<TestStartReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.ReserveBike);
await connector.Command.DoReserve(bike);
await listener.ReportStateAsync(State.GeneralStartReservationError, "Context info.");
});
}
/// <summary>
/// Use case: Start reservation.
/// Final state: Reservation failed.
/// </summary>
[Test]
[Ignore("Exception needs to be initialized correctly.")]
public void TestStartReservationTooManyBikesException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var listener = Substitute.For<IStartReservationCommandListener>();
bike.Id.Returns("1543");
BookingDeclinedException.IsBookingDeclined("Too many bikes", out BookingDeclinedException bookingDeclinedException);
bookingDeclinedException.MaxBikesCount.Returns(3);
connector.Command.DoReserve(Arg.Any<IBikeInfoMutable>()).Returns(x
=> throw bookingDeclinedException);
Assert.That(
async () => await InvokeAsync<TestStartReservationCommand>(
bike,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener),
Throws.InstanceOf<BookingDeclinedException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.ReportStep(Step.ReserveBike);
await connector.Command.DoReserve(bike);
await listener.ReportStateAsync(State.TooManyBikesError, "Too many bikes");
});
}
}
}

View file

@ -0,0 +1,491 @@
using System;
using System.Threading;
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.Repository.Request;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
using ShareeBike.Services.Geolocation;
using Geolocation = ShareeBike.Services.Geolocation.Geolocation;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
using NSubstitute.ExceptionExtensions;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Repository.Exception;
using Newtonsoft.Json;
using ShareeBike.Repository.Response;
using ShareeBike.ViewModel;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
[TestFixture]
public class TestCloseCommand
{
/// <summary>
/// Use case: Close lock
/// </summary>
[Test]
public async Task TestClose()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
await InvokeAsync<TestCloseCommand>(
bike,
geolocation,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null);
// Verify that location is kept because bike might be returned later.
Assert.That(
bike.LockInfo.Location.Latitude,
Is.EqualTo(47.99).Within(0.001));
Assert.That(
bike.LockInfo.Location.Longitude,
Is.EqualTo(7.78).Within(0.001));
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Closed));
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
listener.Received().ReportStep(Step.WaitStopPollingQueryLocation);
listener.Received().ReportStep(Step.QueryLocationTerminated);
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
}
[Test]
public async Task TestCloseGeolocationServiceGetAsyncFails()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
var startOfTest = DateTime.Now;
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Throws(new Exception("Ups no location..."));
locks[0].CloseAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked);
await InvokeAsync<TestCloseCommand>(
bike,
geolocation,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null);
// Verify that location is kept because bike might be returned later.
Assert.That(
bike.LockInfo.Location,
Is.Null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
await listener.Received().ReportStateAsync(State.StartGeolocationException, "Ups no location...");
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
});
}
[Test]
public void TestCloseCloseFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(
bike,
geolocation,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null),
Throws.InstanceOf<OutOfReachException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.Received().ReportStateAsync(State.OutOfReachError, "Exception of type 'ShareeBike.Services.BluetoothLock.Exception.OutOfReachException' was thrown.");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public void TestCloseCloseFailsCouldntCloseMovingException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseMovingException());
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(
bike, geolocation, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntCloseMovingException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.Received().ReportStateAsync(State.CouldntCloseMovingError, "The process is motion sensitive. Step close to the lock, do not move, and try again.");
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Open));
}
[Test]
public void TestCloseCloseFailsCouldntCloseBoltBlockedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseBoltBlockedException());
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntCloseBoltBlockedException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.Received().ReportStateAsync(State.CouldntCloseBoltBlockedError, "Lock bolt is blocked. Make sure that no spoke or any other obstacle prevents the lock from closing and try again.");
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestCloseCloseFailsCouldntCloseBoltBlockedExceptionOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseBoltBlockedException(LockingState.Open));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntCloseBoltBlockedException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.Received().ReportStateAsync(State.CouldntCloseBoltBlockedError, "Lock bolt is blocked. Make sure that no spoke or any other obstacle prevents the lock from closing and try again.");
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Open));
}
[Test]
public void TestCloseCloseFailsCouldntCloseInconsistentState()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseInconsistentStateExecption(LockitLockingState.Unknown.GetLockingState()));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntCloseInconsistentStateExecption>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.Received().ReportStateAsync(State.GeneralCloseError, "Lock reports unknown bold position. Lock could be closed or open. Please try again or contact customer support.");
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestCloseCloseFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build());
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
Assert.That(
async () => await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await listener.ReportStateAsync(State.GeneralCloseError, "Exception message.");
await connector.Command.UpdateLockingStateAsync(bike, Arg.Is<LocationDto>(x => x.Latitude == 47.99 && x.Longitude == 7.78));
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public async Task TestCloseWaitGeolocationServiceGetAsyncFails()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
locks[0].CloseAsync()
.Returns(LockitLockingState.Closed); // Return lock state indicating success
geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>()).Returns(Task.FromException<IGeolocation>(new Exception("Ups, some error...")));
bike.State.Value.Returns(InUseStateEnum.Booked);
await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
listener.Received().ReportStep(Step.WaitStopPollingQueryLocation);
await listener.Received().ReportStateAsync(State.WaitGeolocationException, "Ups, some error...");
listener.Received().ReportStep(Step.QueryLocationTerminated);
await connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
});
}
[Test]
public async Task TestCloseUpdateLockingStateFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
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")));
bike.State.Value.Returns(InUseStateEnum.Booked);
await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
[Test]
public async Task TestCloseUpdateLockingStateFailsResponseException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
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."));
bike.State.Value.Returns(InUseStateEnum.Booked);
await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
await listener.ReportStateAsync(State.ResponseIsInvalid, "Outer message.");
});
}
[Test]
public async Task TestCloseUpdateLockingStateFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocationService>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<ICloseCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
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."));
bike.State.Value.Returns(InUseStateEnum.Booked);
await InvokeAsync<TestCloseCommand>(bike, geolocation, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.StartingQueryingLocation);
await geolocation.GetAsync(Arg.Any<CancellationToken?>(), Arg.Any<DateTime?>());
listener.Received().ReportStep(Step.ClosingLock);
await locks.Received()[0].CloseAsync(); // Lock must be closed
await connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>());
await listener.ReportStateAsync(State.BackendUpdateFailed, "Exception message.");
});
}
}
}

View file

@ -0,0 +1,131 @@
using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Repository.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
[TestFixture]
public class TestConnectCommand
{
/// <summary>
/// Use case: Connect lock
/// </summary>
[Test]
public async Task TestConnect()
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IConnectAndGetStateCommandListener>();
bike.LockInfo.Id.Returns(0);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build())); // Return lock state indicating success
await InvokeAsync<TestConnectCommand>(
bike,
locks,
listener);
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Closed));
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.ConnectLock);
await locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
listener.Received().ReportStep(Step.GetLockingState);
});
}
/// <summary>
/// Use case: Connect lock, lock out of reach
/// </summary>
[Test]
public void TestConnectOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IConnectAndGetStateCommandListener>();
var timeOuts = Substitute.For<ITimeOutProvider>();
bike.LockInfo.Id.Returns(0);
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<LockInfoTdo>(x => throw new OutOfReachException()); // Return exception
locks.TimeOut.Returns(timeOuts);
Assert.That(
async () => await InvokeAsync<TestConnectCommand>(
bike,
locks,
listener),
Throws.InstanceOf<OutOfReachException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.ConnectLock);
await locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
await listener.Received().ReportStateAsync(State.OutOfReachError, "Exception of type 'ShareeBike.Services.BluetoothLock.Exception.OutOfReachException' was thrown.");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
/// <summary>
/// Use case: Connect lock
/// </summary>
[Test]
public void TestConnectException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IConnectAndGetStateCommandListener>();
var timeOuts = Substitute.For<ITimeOutProvider>();
bike.Id.Returns("0");
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<LockInfoTdo>(x => throw new Exception("Ups...")); // Return exception
locks.TimeOut.Returns(timeOuts);
Assert.That(
async () => await InvokeAsync<TestConnectCommand>(
bike,
locks,
listener),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.ConnectLock);
await locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
await listener.Received().ReportStateAsync(State.GeneralConnectLockError, "Please step as close as possible to the bike lock and try again.");
await locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
await listener.Received().ReportStateAsync(State.GeneralConnectLockError, "Your mobile device still does not connect to the bike lock. Please restart the app or even your mobile device and repeat the process.");
await locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
await listener.Received().ReportStateAsync(State.GeneralConnectLockError, "It is still not possible to establish a connection between your mobile device and the bike lock. Please contact customer support!\r\n\r\nAlternative:\r\n1. close app,\r\n2. press the button at the top of the lock briefly and release it as soon as it starts flashing,\r\n3. make sure that the lock is completely closed and remains closed.\r\n4. send e-mail to operator (otherwise your chargeable rental will continue!): Please include problem description, bike-id and drop-off station.");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
}
}

View file

@ -0,0 +1,82 @@
using System;
using System.Threading.Tasks;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
using ShareeBike.Services.BluetoothLock.Exception;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
[TestFixture]
public class TestDisconnectCommand
{
/// <summary>
/// Use case: Disconnect lock
/// </summary>
[Test]
public async Task TestDisconnect()
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IDisconnectCommandListener>();
bike.LockInfo.Id.Returns(0);
bike.LockInfo.State.Returns(LockingState.Closed);
await locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
await InvokeAsync<TestDisconnectCommand>(
bike,
locks,
listener);
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.DisconnectLock);
await locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
});
}
/// <summary>
/// Use case: Disconnect lock
/// </summary>
[Test]
public async Task TestDisconnectException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IDisconnectCommandListener>();
bike.LockInfo.Id.Returns(0);
bike.LockInfo.State.Returns(LockingState.Closed);
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>())
.Returns<Task>(x => throw new Exception("exception"));
await InvokeAsync<TestDisconnectCommand>(
bike,
locks,
listener);
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Closed));
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.DisconnectLock);
await locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
await listener.Received().ReportStateAsync(State.GeneralDisconnectError,"exception");
});
}
}
}

View file

@ -0,0 +1,329 @@
using System;
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.Repository.Request;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
using static ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
using ShareeBike.Services.BluetoothLock.Exception;
using ShareeBike.Repository.Exception;
using Newtonsoft.Json;
using ShareeBike.Repository.Response;
using ShareeBike.ViewModel;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.BluetoothLock.Command
{
[TestFixture]
public class TestOpenCommand
{
/// <summary>
/// Use case: Open lock
/// </summary>
[Test]
public async Task TestOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await connector.Command.UpdateLockingStateAsync(bike);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Open));
}
[Test]
public void TestOpenOpenFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null),
Throws.InstanceOf<OutOfReachException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.OutOfReachError, "Exception of type 'ShareeBike.Services.BluetoothLock.Exception.OutOfReachException' was thrown.");
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public void TestOpenOpenFailsBoltStatusUnknownException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldStatusIsUnknownException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(
bike,
locks,
() => true, // isConnectedDelegate
(isConnected) => connector,
listener, null),
Throws.InstanceOf<CouldntOpenBoldStatusIsUnknownException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenBoldStatusIsUnknownError, "Position of lock bolt is unknown. Lock could be closed or open. Please try again or contact customer support.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestOpenOpenFailsCouldntOpenBoltBlockedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldIsBlockedException());
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntOpenBoldIsBlockedException>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenBoldIsBlockedError, "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownFromHardwareError));
}
[Test]
public void TestOpenOpenFailsCouldntOpenInconsistentStateException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenInconsistentStateExecption(LockitLockingState.Closed.GetLockingState()));
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<CouldntOpenInconsistentStateExecption>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.CouldntOpenInconsistentStateError, "Unexpected locking state \"Closed\" detected after sending open command. Please try again or contact customer support.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.Closed));
}
[Test]
public void TestOpenOpenFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
locks[0].OpenAsync()
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Closed);
Assert.That(
async () => await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null),
Throws.InstanceOf<Exception>());
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
await listener.ReportStateAsync(State.GeneralOpenError, "Exception message.");
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.UpdateLockingState);
});
Assert.That(
bike.LockInfo.State,
Is.EqualTo(LockingState.UnknownDisconnected));
}
[Test]
public async Task TestOpenUpdateLockingStateFailsWebConnectFailure()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x => throw new WebConnectFailureException("Context info.", new System.Exception("hoppla")));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await listener.ReportStateAsync(State.WebConnectFailed, "Context info.");
});
}
[Test]
public async Task TestOpenUpdateLockingStateFailsInvalidResponse()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
connector.Command.UpdateLockingStateAsync(bike, Arg.Any<LocationDto>()).Returns(x =>
throw new ReturnBikeException(JsonConvert.DeserializeObject<DoReturnResponse>(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message."));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await listener.ReportStateAsync(State.ResponseIsInvalid, "Outer message.");
});
}
[Test]
public async Task TestOpenUpdateLockingStateFails()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var locks = Substitute.For<ILocksService>();
var listener = Substitute.For<IOpenCommandListener>();
var viewUpdateManager = Substitute.For<IPollingUpdateTaskManager>();
locks[0].OpenAsync()
.Returns(LockitLockingState.Open); // Return lock state indicating success
connector.Command.UpdateLockingStateAsync(bike).Returns(x => throw new Exception("Exception message."));
await InvokeAsync<TestOpenCommand>(bike, locks, () => true, (isConnected) => connector, listener, null);
// Verify behavior
Received.InOrder(async () =>
{
listener.Received().ReportStep(Step.OpeningLock);
await locks.Received()[0].OpenAsync(); // Lock must be open
listener.Received().ReportStep(Step.GetLockInfos);
listener.Received().ReportStep(Step.WaitStopPolling);
listener.Received().ReportStep(Step.UpdateLockingState);
await connector.Command.UpdateLockingStateAsync(bike);
await listener.ReportStateAsync(State.BackendUpdateFailed, "Exception message.");
});
}
}
}

View file

@ -0,0 +1,101 @@
using System;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
using ShareeBike.Model.State;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BluetoothLock
{
[TestFixture]
public class TestBikeInfo
{
[Test]
public void TestCtorCopyNull() =>
Assert.Throws<ArgumentException>(
() => new BikeInfo(null, null),
"Verify that no unspecific reference not set to... exception is thrown");
[Test]
public void TestCtorAvailable()
{
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "13").Id, Is.EqualTo("12"));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "13").StationId, Is.EqualTo("13"));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "13").State.Value, Is.EqualTo(InUseStateEnum.Disposable));
}
[Test]
public void TestCtorAvailableBikeNull()
{
Assert.That(
() => new BikeInfo(
null,
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
5200544,
new Guid("00000000-0000-0000-0000-000000000001"),
"13"),
Throws.ArgumentNullException);
}
[Test]
public void TestCtorRequested()
{
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null, null, dateTimeProvider: () => new DateTime(2019, 1, 1), false /*isDemo*/, null /*group*/).Id, Is.EqualTo("12"));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null, null, dateTimeProvider: () => new DateTime(2019, 1, 1), false /*isDemo*/, null /*group*/).LockInfo.Id, Is.EqualTo(112));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null, null, dateTimeProvider: () => new DateTime(2019, 1, 1), false /*isDemo*/, null /*group*/).State.Value, Is.EqualTo(InUseStateEnum.Reserved));
}
[Test]
public void TestCtorRequestedBikeNull()
{
Assert.That(
() => new BikeInfo(
null,
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
112,
new Guid(),
null,
null,
null,
new DateTime(2020, 1, 1),
"a@b",
"13",
null,
null,
dateTimeProvider: () => new DateTime(2019, 1, 1),
false /*isDemo*/,
null /*group*/),
Throws.ArgumentNullException);
}
[Test]
public void TestCtorBooked()
{
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null /*operator uri*/).Id, Is.EqualTo("12"));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null /*operator uri*/).LockInfo.Id, Is.EqualTo(112));
Assert.That(new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("12", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 112, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b", "13", null /*operator uri*/).State.Value, Is.EqualTo(InUseStateEnum.Booked));
}
[Test]
public void TestCtorBookedNull()
{
Assert.That(
() => new BikeInfo(
null,
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
112,
new Guid(),
null,
null,
null,
new DateTime(2020, 1, 1),
"a@b",
"13",
null /*operator uri*/),
Throws.ArgumentNullException);
}
}
}

View file

@ -0,0 +1,79 @@
using System;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
using ShareeBike.Model.Connector;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.Geolocation;
using ShareeBike.ViewModel;
namespace SharedBusinessLogic.Tests.Model.Bike.BluetoothLock
{
[TestFixture]
public class TestBikeInfoMutalbe
{
[Test]
public void TestCtor()
{
Assert.That(
new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike(
"MyBikeId",
ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.LockModel.ILockIt),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
42,
new Guid(),
"17"),
"My Station Name").StationName,
Is.EqualTo("My Station Name"));
}
[Test]
public void TestToString()
{
Assert.That(
new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
new ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike(
"MyBikeId",
ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.LockModel.ILockIt,
ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.WheelType.Trike,
ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.TypeOfBike.Cargo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
42,
new Guid(),
"17"),
"My Station Name").ToString(),
Is.EqualTo("Id=MyBikeId;type=Cargo;state=Disposable;Lock id=42"));
}
[Test]
public void TestCtorBikeNull()
{
Assert.That(
() => new BikeInfoMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
null,
"My Station Name"),
Throws.ArgumentNullException);
}
}
}

View file

@ -0,0 +1,173 @@
using System;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BluetoothLock
{
[TestFixture]
public class TestLockInfo
{
[Test]
public void TestCtor()
{
Assert.That(
new LockInfo.Builder { Id = 123 }.Build().State, Is.EqualTo(LockingState.UnknownDisconnected));
Assert.That(
new LockInfo.Builder { Id = 123 }.Build().Id, Is.EqualTo(123));
}
[Test]
public void TestEquals()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build(), Is.True);
}
[Test]
public void TestEqualsFalse_Id()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 3,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build(), Is.False);
}
[Test]
public void TestEqualsFalse_Guid()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("1000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build(), Is.False);
}
[Test]
public void TestEqualsFalse_Seed()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 5, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build(), Is.False);
}
[Test]
public void TestEqualsFalse_UserKey()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 9, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build(), Is.False);
}
[Test]
public void TestEqualsFalse_AdminKey()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 11, 1 },
State = LockingState.Closed
}.Build(), Is.False);
}
[Test]
public void TestEqualsFalse_LockingState()
{
Assert.That(new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Closed
}.Build() == new LockInfo.Builder
{
Id = 2,
Guid = new Guid("0000f00d-1212-efde-1523-785fef13d123"),
Seed = new byte[] { 1, 2 },
UserKey = new byte[] { 7, 2 },
AdminKey = new byte[] { 2, 1 },
State = LockingState.Open
}.Build(), Is.False);
}
}
}

View file

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.BluetoothLock.Tdo;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BluetoothLock
{
[TestFixture]
public class TestLockInfoHelper
{
[Test]
public void TestUpdateById_State()
{
var locksInfo = new List<LockInfo> {
new LockInfo.Builder { Id = 12, Seed = new byte[] { 3, 5 }, UserKey = new byte[] {2, 1 }, State = LockingState.UnknownFromHardwareError }.Build(),
new LockInfo.Builder { Id = 14, Seed = new byte[] { 3, 1 }, UserKey = new byte[] {2, 7 }, State = LockingState.Open }.Build(),
new LockInfo.Builder { Id = 3, Seed = new byte[] { 1, 5 }, UserKey = new byte[] {2, 9 }, State = LockingState.Closed }.Build(),
};
var locksInfoTdo = new List<LockInfoTdo> {
new LockInfoTdo.Builder { Id =14, State = LockitLockingState.Closed}.Build()
};
var resultList = locksInfo.UpdateById(locksInfoTdo);
var result = resultList.FirstOrDefault(x => x.Id == 14);
Assert.That(result, Is.Not.Null, "Target element was removed.");
Assert.That(result.State, Is.EqualTo(LockingState.Closed));
}
[Test]
public void TestUpdateById_Guid()
{
var locksInfo = new List<LockInfo> {
new LockInfo.Builder { Id = 12, Seed = new byte[] { 3, 5 }, UserKey = new byte[] {2, 1 }, State = LockingState.UnknownFromHardwareError }.Build(),
new LockInfo.Builder { Id = 14, Seed = new byte[] { 3, 1 }, UserKey = new byte[] {2, 7 }, State = LockingState.Open }.Build(),
new LockInfo.Builder { Id = 3, Seed = new byte[] { 1, 5 }, UserKey = new byte[] {2, 9 }, State = LockingState.Closed }.Build(),
};
var locksInfoTdo = new List<LockInfoTdo> {
new LockInfoTdo.Builder { Id =14, Guid = new System.Guid("00000000-0000-0000-0000-e57e6b9aee16"), State = LockitLockingState.Open}.Build()
};
var resultList = locksInfo.UpdateById(locksInfoTdo);
var result = resultList.FirstOrDefault(x => x.Id == 14);
Assert.That(result, Is.Not.Null, "Target element was removed.");
Assert.That(result.Guid, Is.EqualTo(new Guid("00000000-0000-0000-0000-e57e6b9aee16")));
}
}
}

View file

@ -0,0 +1,122 @@
using System;
using System.Linq;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
using ShareeBike.Services.Geolocation;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BluetoothLock
{
[TestFixture]
public class TestLockInfoMutable
{
[Test]
public void TestCtor()
{
var lockInfo = new LockInfoMutable(
1,
new Guid("00000000-0000-0000-0000-e57e6b9aee16"),
new byte[] { 1, 2, 3 }, // User key
new byte[] { 1, 23 }, // Admin key
new byte[] { 1, 12 }, // Seed
LockingState.Closed);
Assert.That(lockInfo.Id, Is.EqualTo(1));
Assert.That(lockInfo.Guid, Is.EqualTo(new Guid("00000000-0000-0000-0000-e57e6b9aee16")));
Assert.That((new byte[] { 1, 2, 3 }).SequenceEqual(lockInfo.UserKey), Is.True);
Assert.That((new byte[] { 1, 23 }).SequenceEqual(lockInfo.AdminKey), Is.True);
Assert.That((new byte[] { 1, 12 }).SequenceEqual(lockInfo.Seed), Is.True);
Assert.That(lockInfo.State, Is.EqualTo(LockingState.Closed));
}
[Test]
public void TestSetGuid()
{
var lockInfo = new LockInfoMutable(1, new Guid(), new byte[] { 1, 2, 3 }, new byte[] { 1, 23 }, new byte[] { 1, 12 }, LockingState.Closed);
lockInfo.Guid = new Guid("00000000-0000-0000-0000-e57e6b9aee16");
Assert.That(lockInfo.Guid, Is.EqualTo(new Guid("00000000-0000-0000-0000-e57e6b9aee16")));
}
[Test]
public void TestLoad()
{
var lockInfo = new LockInfoMutable(
2,
new Guid(),
new byte[] { 5, 4 }, // User key
new byte[] { 14, 223 }, // Admin key
new byte[] { 3, 4, 5 }, // Seed
LockingState.Closed);
lockInfo.Load(
1,
new Guid("00000000-0000-0000-0000-e57e6b9aee16"),
new byte[] { 1, 12 }, // Seed
new byte[] { 1, 2, 3 }, // User key)
new byte[] { 1, 23 });
Assert.That(lockInfo.Id, Is.EqualTo(1));
Assert.That(lockInfo.Guid, Is.EqualTo(new Guid("00000000-0000-0000-0000-e57e6b9aee16")));
Assert.That((new byte[] { 1, 2, 3 }).SequenceEqual(lockInfo.UserKey), Is.True);
Assert.That((new byte[] { 1, 23 }).SequenceEqual(lockInfo.AdminKey), Is.True);
Assert.That((new byte[] { 1, 12 }).SequenceEqual(lockInfo.Seed), Is.True);
Assert.That(lockInfo.State, Is.EqualTo(LockingState.Closed));
}
[Test]
public void TestLastLockingStateChange()
=> Assert.That(
new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13)).LastLockingStateChange,
Is.Null);
[Test]
public void TestLastLockingStateChangeCangeCtor()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.State = LockingState.Closed;
Assert.That(
lockInfo.LastLockingStateChange,
Is.EqualTo(new DateTime(2023, 03, 13)));
}
[Test]
public void TestLocationCtor()
=> Assert.That(
new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13)).Location,
Is.Null);
[Test]
public void TestLocation()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.Location = new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78}.Build();
// Verify that location is kept because bike might be returned later.
Assert.That(
lockInfo.Location.Latitude,
Is.EqualTo(47.99).Within(0.001));
Assert.That(
lockInfo.Location.Longitude,
Is.EqualTo(7.78).Within(0.001));
}
[Test]
public void TestLocationStateChange()
{
var lockInfo = new LockInfoMutable(1, new Guid(), null, null, null, LockingState.Open, () => new DateTime(2023, 03, 13));
lockInfo.Location = new Geolocation.Builder { Latitude = 47.99, Longitude = 7.78 }.Build();
lockInfo.State = LockingState.Closed;
// Verify that location is kept because bike might be returned later.
Assert.That(
lockInfo.Location,
Is.Null);
}
}
}

View file

@ -0,0 +1,93 @@
using System;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
namespace SharedBusinessLogic.Tests.Model.Bike.CopriLock
{
[TestFixture]
public class TestBikeInfo
{
[Test]
public void TestCtorAvailable()
{
var bike = new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("bikeId", LockModel.Sigo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"stationId",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo());
Assert.That(
bike.State.Value,
Is.EqualTo(ShareeBike.Model.State.InUseStateEnum.Disposable));
}
[Test]
public void TestCtorAvailableBikeNull()
{
Assert.That(
() => new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
null,
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"stationId",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo()),
Throws.ArgumentNullException);
}
[Test]
public void TestCtorFeedbackRequired()
{
var bike = new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("bikeId", LockModel.Sigo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"stationId",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
true);
Assert.That(
bike.State.Value,
Is.EqualTo(ShareeBike.Model.State.InUseStateEnum.FeedbackPending));
}
[Test]
public void TestCtorRequestedBikeNull()
{
Assert.That(
() => new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
null,
new DriveMutable(),
DataSource.Copri,
DateTime.Now,
"a@b",
"stationId",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
new Uri("https://sharee.bike"),
new RentalDescription(),
() => DateTime.Now),
Throws.ArgumentNullException);
}
[Test]
public void TestCtorOccupiedBikeNull()
{
Assert.That(
() => new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
null,
new DriveMutable(),
DataSource.Copri,
DateTime.Now,
"a@b",
"stationId",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
new Uri("https://sharee.bike"),
new RentalDescription()),
Throws.ArgumentNullException);
}
}
}

View file

@ -0,0 +1,12 @@
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
namespace SharedBusinessLogic.Tests.Model.Bike.CopriLock
{
[TestFixture]
public class TestBikeInfoMutable
{
}
}

View file

@ -0,0 +1,49 @@
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
namespace SharedBusinessLogic.Tests.Model.BikeInfo.DriveNS.BatteryNS
{
[TestFixture]
public class TestBattery
{
[Test]
public void TestSetCurrentChargePercent() => Assert.That(
new Battery.Builder { CurrentChargePercent = 20 }.Build().CurrentChargePercent,
Is.EqualTo(20.0));
[Test]
public void TestSetCurrentChargePercentOutOfRange() => Assert.That(
new Battery.Builder { CurrentChargePercent = 101 }.Build().CurrentChargePercent,
Is.NaN);
[Test]
public void TestSetCurrentChargeBars() => Assert.That(
new Battery.Builder { CurrentChargeBars = 21, MaxChargeBars = 22 }.Build().CurrentChargeBars,
Is.EqualTo(21));
[Test]
public void TestSetCurrentChargeBarsOutOfRange() => Assert.That(
new Battery.Builder { CurrentChargeBars = -1, MaxChargeBars = 22 }.Build().CurrentChargeBars,
Is.Null);
[Test]
public void TestSetMaxChargeBars() => Assert.That(
new Battery.Builder { MaxChargeBars = 23 }.Build().MaxChargeBars,
Is.EqualTo(23));
[Test]
public void TestSetMaxChargeBarsOutOfRange() => Assert.That(
new Battery.Builder { MaxChargeBars = -1 }.Build().MaxChargeBars,
Is.Null);
[Test]
public void TestSetCurrentChargeBarsNoMaxValueSet() => Assert.That(
new Battery.Builder { CurrentChargeBars = 21 }.Build().CurrentChargeBars,
Is.Null);
[Test]
public void TestSetCurrentChargeBars_CurrentValueTooLarge() => Assert.That(
new Battery.Builder { CurrentChargeBars = 25, MaxChargeBars = 22 }.Build().CurrentChargeBars,
Is.Null);
}
}

View file

@ -0,0 +1,93 @@
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
namespace SharedBusinessLogic.Tests.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS
{
[TestFixture]
public class TestBatteryMutable
{
[Test]
public void TestCurrentChargeBars()
{
var battery = new BatteryMutable(new Battery.Builder {
MaxChargeBars = 5,
CurrentChargeBars = 1,
CurrentChargePercent = 20.0
}.Build());
battery.CurrentChargeBars = 4;
Assert.That(
battery.CurrentChargeBars,
Is.EqualTo(4));
Assert.That(
battery.CurrentChargePercent,
Is.EqualTo(80.0));
}
[Test]
public void TestCurrentChargeBarsNull()
{
var battery = new BatteryMutable(new Battery.Builder
{
MaxChargeBars = 5,
CurrentChargeBars = 1,
CurrentChargePercent = 20.0
}.Build());
battery.CurrentChargeBars = null;
Assert.That(
battery.CurrentChargeBars,
Is.Null);
Assert.That(
battery.CurrentChargePercent,
Is.EqualTo(double.NaN));
}
[Test]
public void TestCurrentChargeBarsInvalidStateZero()
{
var battery = new BatteryMutable(new Battery.Builder
{
MaxChargeBars = 0, // Could lead to division by zero if not handled correctly.
CurrentChargeBars = null,
CurrentChargePercent = 20.0
}.Build());
battery.CurrentChargeBars = 4;
Assert.That(
battery.CurrentChargeBars,
Is.Null);
Assert.That(
battery.CurrentChargePercent,
Is.EqualTo(20.0));
}
[Test]
public void TestCurrentChargeBarsInvalidStateNull()
{
var battery = new BatteryMutable(new Battery.Builder
{
MaxChargeBars = null,
CurrentChargeBars = null,
CurrentChargePercent = 20.0
}.Build());
battery.CurrentChargeBars = 4;
Assert.That(
battery.CurrentChargeBars,
Is.Null);
Assert.That(
battery.CurrentChargePercent,
Is.EqualTo(20.0));
}
}
}

View file

@ -0,0 +1,50 @@
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
using DriveType = ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.DriveType;
namespace SharedBusinessLogic.Tests.Model.BikeInfo.DriveNS
{
[TestFixture]
public class TestDriveMutable
{
[Test]
public void TestCtorNoArgs()
{
var drive = new DriveMutable();
Assert.That(
drive.Type,
Is.EqualTo(DriveType.SoleHumanPowered));
Assert.That(
drive.Engine,
Is.Not.Null);
Assert.That(
drive.Battery,
Is.Not.Null);
}
[Test]
public void TestCtor()
{
var engine = Substitute.For<IEngine>();
var battery = Substitute.For<IBattery>();
engine.Manufacturer.Returns("Bosch");
battery.CurrentChargePercent.Returns(97);
var drive = new DriveMutable(engine, battery);
Assert.That(
drive.Engine.Manufacturer,
Is.EqualTo("Bosch"));
Assert.That(
drive.Battery.CurrentChargePercent,
Is.EqualTo(97));
}
}
}

View file

@ -0,0 +1,46 @@
using NUnit.Framework;
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike
{
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
[TestFixture]
public class TestBike
{
[Test]
public void TestConstruct()
{
var l_oBike = new Bike("43", LockModel.ILockIt);
Assert.That(l_oBike.Id, Is.EqualTo("43"));
Assert.That(l_oBike.TypeOfBike, Is.EqualTo(null));
Assert.That(l_oBike.WheelType, Is.EqualTo(null));
l_oBike = new Bike("43", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Cargo);
Assert.That(l_oBike.Id, Is.EqualTo("43"));
Assert.That(l_oBike.TypeOfBike, Is.EqualTo(TypeOfBike.Cargo));
Assert.That(l_oBike.WheelType, Is.EqualTo(WheelType.Mono));
}
[Test]
public void TestCompare()
{
var l_oBike1 = new Bike("43", LockModel.ILockIt);
Assert.That(l_oBike1.Id, Is.EqualTo("43"));
Assert.That(l_oBike1.TypeOfBike, Is.EqualTo(null));
Assert.That(l_oBike1.WheelType, Is.EqualTo(null));
var l_oBike2 = new Bike("42", LockModel.ILockIt, WheelType.Two, TypeOfBike.Allround);
Assert.That(l_oBike1 == l_oBike2, Is.False);
l_oBike2 = new Bike("43", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround);
Assert.That(l_oBike1 == l_oBike2, Is.False);
l_oBike2 = new Bike("43", LockModel.ILockIt, WheelType.Two, TypeOfBike.Cargo);
Assert.That(l_oBike1 == l_oBike2, Is.False);
l_oBike2 = new Bike("43", LockModel.ILockIt, null, null);
Assert.That(l_oBike1 == l_oBike2, Is.True);
}
}
}

View file

@ -0,0 +1,21 @@
using NUnit.Framework;
using ShareeBike.Model.Bikes;
namespace SharedBusinessLogic.Tests
{
[TestFixture]
public class TestBikeCollection
{
/// <summary> Tests the member.</summary>
[Test]
public void TestConstruct()
{
var l_oColl = new BikeCollection();
Assert.That(l_oColl.Count, Is.EqualTo(0));
Assert.That(l_oColl.GetById("1"), Is.Null);
}
}
}

View file

@ -0,0 +1,364 @@
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using ShareeBike.Model.Bikes;
using ShareeBike.Model.Bikes.BikeInfoNS;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
using ShareeBike.Model.Connector;
using ShareeBike.Model.Connector.Updater;
using ShareeBike.Model.State;
using ShareeBike.Model.Stations;
using ShareeBike.Model.Stations.StationNS;
using ShareeBike.Services.BluetoothLock;
using ShareeBike.Services.Geolocation;
using ShareeBike.ViewModel;
using BikeInfo = ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfo;
namespace SharedBusinessLogic.Tests
{
[TestFixture]
public class TestBikeCollectionMutable
{
private class BikeInfoMutable : ShareeBike.Model.Bikes.BikeInfoNS.BC.BikeInfoMutable
{
public BikeInfoMutable(
string id,
LockModel lockType,
bool isDemo = false,
IEnumerable<string> group = null,
WheelType? wheelType = null,
TypeOfBike? typeOfBike = null,
AaRideType? aaRideType = null,
string description = null,
string stationId = null,
string stationName = null,
Uri operatorUri = null,
RentalDescription tariffDescription = null,
Func<DateTime> dateTimeProvider = null,
IStateInfo stateInfo = null) : base(
new Bike(id, lockType, wheelType, typeOfBike, aaRideType, description),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
isDemo,
group,
stationId,
stationName,
operatorUri,
tariffDescription,
dateTimeProvider,
stateInfo)
{
}
}
/// <summary> Tests the member.</summary>
[Test]
public void TestAdd()
{
var l_oColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>());
l_oColl.Add(new BikeInfoMutable("57", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Allround));
Assert.Throws<Exception>(() => l_oColl.Add(new BikeInfoMutable("57", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Cargo)));
}
[Test]
public void TestUpdate_Null()
{
var l_oBikeRequested = new BikeInfoMutable("20", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Allround);
l_oBikeRequested.State.Load(new StateInfo(() => DateTime.Now, DateTime.Now, TimeSpan.FromMinutes(15), "john@long", "1234"));
var l_oBikeColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>())
{
new BikeInfoMutable("63", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Allround),
new BikeInfoMutable("57", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Cargo),
l_oBikeRequested,
};
// Verify initial state
Assert.That(l_oBikeColl.GetById("63"), Is.Not.Null);
Assert.That(l_oBikeColl.GetById("57").State.Value, Is.EqualTo(InUseStateEnum.Disposable));
Assert.That(l_oBikeColl.GetById("20").State.Value, Is.EqualTo(InUseStateEnum.Reserved));
Assert.That(l_oBikeColl.GetById("33"), Is.Null);
l_oBikeColl.Update(null, null);
// Verify modified state
Assert.That(l_oBikeColl.GetById("63"), Is.Null);
Assert.That(l_oBikeColl.GetById("57"), Is.Null);
Assert.That(l_oBikeColl.GetById("20"), Is.Null);
Assert.That(l_oBikeColl.GetById("33"), Is.Null);
}
[Test]
public void TestUpdate()
{
var bikeRequested = new BikeInfoMutable("20", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Allround);
bikeRequested.State.Load(new StateInfo(() => DateTime.Now, DateTime.Now, TimeSpan.FromMinutes(15), "john@long", "1234"));
var bikeColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>())
{
new BikeInfoMutable("63", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Allround),
new BikeInfoMutable("57", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Cargo),
bikeRequested,
};
// Verify initial state
Assert.That(bikeColl.GetById("63"), Is.Not.Null); // Will be removed
Assert.That(bikeColl.GetById("57").State.Value, Is.EqualTo(InUseStateEnum.Disposable)); // Will be requested
Assert.That(bikeColl.GetById("20").State.Value, Is.EqualTo(InUseStateEnum.Reserved)); // Will be booked
Assert.That(bikeColl.GetById("33"), Is.Null); //
var bikeResponse = new List<BikeInfo>
{
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike("57", LockModel.ILockIt),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
DateTime.Now,
"john@long",
"7" /*station id*/,
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
null),
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike("20", LockModel.ILockIt),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
DateTime.Now,
"john@long",
"7",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
null),
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike("33", LockModel.Sigo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"7",
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo()),
};
bikeColl.Update(bikeResponse, new List<IStation>());
// Verify modified state
Assert.That(bikeColl.GetById("63"), Is.Null, "Bike not contained in response must not exist.");
Assert.That(bikeColl.GetById("57").State.Value, Is.EqualTo(InUseStateEnum.Booked));
Assert.That(bikeColl.GetById("20").State.Value, Is.EqualTo(InUseStateEnum.Booked));
Assert.That(bikeColl.GetById("33"), Is.Not.Null);
}
/// <summary>
/// Bike for which station name is updated is not contained in bike collection when calling update.
/// </summary>
[Test]
public void TestUpdate_StationName_NewBike()
{
var bikeColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>());
// Verify initial state
Assert.That(bikeColl.GetById("57"), Is.Null);
var l_oBikeResponse = new List<BikeInfo>
{
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike("57", LockModel.Sigo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"7" /*station id*/,
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo()),
};
var stations = new List<IStation>
{
new Station("7", new List<string>(), null, "My fancy station")
};
bikeColl.Update(l_oBikeResponse, stations);
// Verify modified state
Assert.That(bikeColl.GetById("57").StationId, Is.EqualTo("7"));
Assert.That(bikeColl.GetById("57").StationName, Is.EqualTo("My fancy station"));
}
[Test]
public void TestUpdate_StationName_UpdateExistingBike()
{
var bikeColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>())
{
new BikeInfoMutable("57", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Trike, TypeOfBike.Cargo),
};
// Verify initial state
Assert.That(bikeColl.GetById("57"), Is.Not.Null);
var bikeResponse = new List<BikeInfo>
{
new ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfo(
new Bike("57" /* bike id*/, LockModel.ILockIt, WheelType.Trike, TypeOfBike.Allround, AaRideType.NoAaRide, "Test description"),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
17, /* Lock id */
new Guid(),
new byte[0],
new byte[0],
new byte[0],
DateTime.Now,
"john@long,",
"7", /*station id*/
null, /*operator uri*/
null, /* tariff description */
false, /* is demo */
new List<string> {"ShareeBike" } /* group id */
),
};
var stations = new List<IStation>
{
new Station("7", new List<string>(), null, "My fancy station")
};
bikeColl.Update(bikeResponse, stations);
// Verify modified state
Assert.That(bikeColl.GetById("57").StationId, Is.Null, "Station id is only set when update creates BikeInfo object, not when updating object BikeInfo because station name does not change.");
Assert.That(bikeColl.GetById("57").StationName, Is.Null, "Station name is only set when update creates BikeInfo object, not when updating object BikeInfo because station name does not change.");
}
[Test]
public void TestUpdate_StationName_Nullstations()
{
var bikeColl = new BikeCollectionMutable(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>());
var bikeResponse = new List<BikeInfo>
{
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(
new Bike("57", LockModel.Sigo),
new DriveMutable(),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
"7" /*station id*/,
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo(),
operatorUri: null /*operator uri*/),
};
bikeColl.Update(bikeResponse, null);
// Verify modified state
Assert.That(bikeColl.GetById("57").StationId, Is.EqualTo("7"));
Assert.That(bikeColl.GetById("57").StationName, Is.EqualTo(""));
}
[Test]
public void TestCreateBluetoothBike()
{
var bikeInfo = BikeInfoFactory.Create(JsonConvert.DeserializeObject<ShareeBike.Repository.Response.BikeInfoAvailable>(
@"{
""description"" : ""Cargo Long"",
""state"" : ""available"",
""bike"" : ""1"",
""gps"" : { ""latitude"": ""47.669888"", ""longitude"": ""9.167749"" },
""station"" : ""9"",
""system"" : ""Ilockit""
}"),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri);
Assert.That(
BikeCollectionMutable.BikeInfoMutableFactory.Create(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
bikeInfo, "Stat1").GetType(),
Is.EqualTo(typeof(ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfoMutable)));
}
[Test]
public void TestCreateCopriBike()
{
var bikeInfo = BikeInfoFactory.Create(JsonConvert.DeserializeObject<ShareeBike.Repository.Response.BikeInfoAvailable>(
@"{
""description"" : ""Cargo Long"",
""state"" : ""available"",
""bike"" : ""1"",
""gps"" : { ""latitude"": ""47.669888"", ""longitude"": ""9.167749"" },
""station"" : ""9"",
""system"" : ""SIGO""
}"),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri);
Assert.That(
BikeCollectionMutable.BikeInfoMutableFactory.Create(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
bikeInfo, "Stat1").GetType(),
Is.EqualTo(typeof(ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfoMutable)));
}
[Test]
public void TestCreateBCBike()
{
var bikeInfo = BikeInfoFactory.Create(JsonConvert.DeserializeObject<ShareeBike.Repository.Response.BikeInfoAvailable>(
@"{
""description"" : ""Cargo Long"",
""state"" : ""available"",
""bike"" : ""1"",
""gps"" : { ""latitude"": ""47.669888"", ""longitude"": ""9.167749"" },
""station"" : ""9"",
""system"" : ""LOCK""
}"),
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri);
Assert.That(
BikeCollectionMutable.BikeInfoMutableFactory.Create(
Substitute.For<IGeolocationService>(),
Substitute.For<ILocksService>(),
() => false /* not connected */,
(_) => Substitute.For<IConnector>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
bikeInfo, "Stat1"),
Is.Null);
}
}
}

View file

@ -0,0 +1,67 @@
using NUnit.Framework;
using ShareeBike.Model.Bike;
using Newtonsoft.Json;
using ShareeBike.Model.State;
using System.Collections.Generic;
using BikeInfoMutable = ShareeBike.Model.Bike.BC.BikeInfoMutable;
namespace SharedBusinessLogic.Tests
{
/// <summary>
/// Exclude from build beause serialization... see below.
/// </summary>
[TestFixture]
public class TestBikeCollectionSerializeJSON
{
[Test, Ignore("Disabled because serialization does no more work due to inheritance since commit ec14b93b.")]
public void Test_SerializeJSON()
{
var l_oCollSource = new BikeCollectionMutable
{
new BikeInfoMutable(57, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Allround)
};
// Verify prerequisites.
Assert.AreEqual(1, l_oCollSource.Count);
Assert.AreEqual(57, l_oCollSource[0].Id);
Assert.AreEqual(InUseStateEnum.Disposable, l_oCollSource[0].State.Value);
Assert.IsNull(l_oCollSource[0].State.MailAddress);
Assert.IsNull(l_oCollSource[0].State.Code);
Assert.IsNull(l_oCollSource[0].State.From);
// Serialize object and verify json
var l_oDetected = JsonConvert.SerializeObject(l_oCollSource, Formatting.Indented, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
const string EXPECTED = @"
[
{
""Id"": 57,
""CurrentStation"": null,
""WheelType"": 1,
""TypeOfBike"": 0,
""State"": {
""StateInfoObject"": {
""$type"": ""ShareeBike.Model.State.StateAvailableInfo, SharedBusinessLogic""
}
}
}
]";
Assert.AreEqual(
TestHelper.PrepareXmlForStringCompare(EXPECTED),
TestHelper.PrepareXmlForStringCompare(l_oDetected));
// Deserialize object.
var l_oBikeCollectionTarget = JsonConvert.DeserializeObject<BikeCollectionMutable>(l_oDetected, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });
// Verify state.
Assert.AreEqual(1, l_oBikeCollectionTarget.Count);
Assert.AreEqual(57, l_oBikeCollectionTarget[0].Id);
Assert.AreEqual(InUseStateEnum.Disposable, l_oBikeCollectionTarget[0].State.Value);
Assert.IsNull(l_oBikeCollectionTarget[0].State.MailAddress);
Assert.IsNull(l_oBikeCollectionTarget[0].State.Code);
Assert.IsNull(l_oBikeCollectionTarget[0].State.From);
}
}
}

View file

@ -0,0 +1,26 @@
using System;
using NUnit.Framework;
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
namespace SharedBusinessLogic.Tests.Model.Bike
{
[TestFixture]
public class TestBikeExtension
{
[Test]
public void TestGetType()
{
Assert.That(LockModel.Sigo.GetLockType(), Is.EqualTo(LockType.Backend));
Assert.That(LockModel.ILockIt.GetLockType(), Is.EqualTo(LockType.Bluethooth));
Assert.That(
() => LockModel.BordComputer.GetLockType(),
Throws.InstanceOf<ArgumentException>());
}
[Test]
public void TestGetTypeCount()
{
Assert.That(Enum.GetValues(typeof(LockModel)).Length, Is.EqualTo(3), $"Impelemtation of {nameof(BikeExtension.GetLockType)} must be updated.");
}
}
}