mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-07-07 12:06:43 +02:00
Version 3.0.381
This commit is contained in:
parent
f963c0a219
commit
3a363acf3a
1525 changed files with 60589 additions and 125098 deletions
|
@ -0,0 +1,241 @@
|
|||
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.Bikes.BikeInfoNS.DriveNS;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Model.User.Account;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using Xamarin.Forms;
|
||||
|
||||
namespace UITest.Fixtures.ViewModel
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class TestBikeAtStationViewModel
|
||||
{
|
||||
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,
|
||||
Func<DateTime> dateTimeProvider = null,
|
||||
IStateInfo stateInfo = null) : base(
|
||||
new Bike(id, lockModel, wheelType, typeOfBike, aaRideType, description),
|
||||
new DriveMutable(),
|
||||
ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri,
|
||||
isDemo,
|
||||
group,
|
||||
stationId,
|
||||
stationName,
|
||||
operatorUri,
|
||||
null,
|
||||
dateTimeProvider,
|
||||
stateInfo)
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_NotLoggedIn()
|
||||
{
|
||||
var l_oBike = new BikeInfoMutable("2", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo);
|
||||
|
||||
var l_oStoreMock = new StoreMock(); // Account without user name, password and cookie
|
||||
|
||||
var l_oUser = new User(
|
||||
l_oStoreMock,
|
||||
l_oStoreMock.Load().Result,
|
||||
"123456789"); // Device identifier
|
||||
|
||||
// Verify prerequisites
|
||||
Assert.That(l_oBike.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
|
||||
Assert.That(l_oUser.IsLoggedIn, Is.False);
|
||||
|
||||
// Verify view model.
|
||||
var l_oViewModel = new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
l_oBike,
|
||||
l_oUser,
|
||||
new MyBikeInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { });
|
||||
|
||||
Assert.That(l_oViewModel.Name, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.DisplayId, Is.EqualTo(""));
|
||||
Assert.That(l_oViewModel.Id, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Available."));
|
||||
Assert.That(l_oViewModel.StateColor, Is.EqualTo(Color.Default));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_Reserved()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Reserved(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new BikeAtStationInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Still 15 min. reserved."));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_ReservedWithCopriConnect()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_ReservedWithCopriConnect(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new BikeAtStationInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Code 4asdfA, still 7 min. reserved."));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_Booked()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Booked(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new BikeAtStationInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
Assert.That(
|
||||
l_oViewModel.StateText, Is.EqualTo($"Code 4asdfA, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}."));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_ReservedBySomeoneElse()
|
||||
{
|
||||
var l_oBike = new BikeInfoMutable("2", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo, AaRideType.NoAaRide, "Test description", "3");
|
||||
|
||||
l_oBike.State.Load(
|
||||
InUseStateEnum.Reserved,
|
||||
new DateTime(2017, 10, 24, 21, 49, 3),
|
||||
TimeSpan.FromMinutes(15),
|
||||
"ragu@gnu-systems.de",
|
||||
"4asdfA");
|
||||
|
||||
var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, false, "987654321" /* session cookie */, new List<string> { "ShareeBike" }));
|
||||
|
||||
var l_oViewModel = new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
l_oBike,
|
||||
new User(
|
||||
l_oStoreMock,
|
||||
l_oStoreMock.Load().Result,
|
||||
"123456789"), // Device id
|
||||
new BikeAtStationInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { });
|
||||
|
||||
Assert.That(l_oViewModel.Name, Is.EqualTo("Test description"));
|
||||
Assert.That(l_oViewModel.DisplayId, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.Id, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Fahrrad bereits reserviert durch anderen Nutzer."));
|
||||
Assert.That(l_oViewModel.StateColor, Is.EqualTo(Color.Red));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_BookedBySomeoneElse()
|
||||
{
|
||||
var l_oBike = new BikeInfoMutable("2", LockModel.ILockIt, false, new List<string> { "ShareeBike" }, WheelType.Two, TypeOfBike.Cargo, AaRideType.NoAaRide, "Test description", "3");
|
||||
|
||||
l_oBike.State.Load(
|
||||
InUseStateEnum.Booked,
|
||||
new DateTime(2017, 10, 24, 21, 49, 3),
|
||||
TimeSpan.FromMinutes(15),
|
||||
"ragu@gnu-systems.de",
|
||||
"4asdfA");
|
||||
|
||||
var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, false, "987654321" /* session cookie */, new List<string> { "ShareeBike" }));
|
||||
|
||||
var l_oViewModel = new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
l_oBike,
|
||||
new User(
|
||||
l_oStoreMock,
|
||||
l_oStoreMock.Load().Result,
|
||||
"123456789"),
|
||||
new BikeAtStationInUseStateInfoProvider(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { });
|
||||
|
||||
Assert.That(l_oViewModel.Name, Is.EqualTo("Test description"));
|
||||
Assert.That(l_oViewModel.DisplayId, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.Id, Is.EqualTo("2"));
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Fahrrad bereits gebucht durch anderen Nutzer."));
|
||||
Assert.That(l_oViewModel.StateColor, Is.EqualTo(Color.Red));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
|
||||
namespace UITest.Fixtures.ViewModel
|
||||
{
|
||||
|
||||
[TestFixture]
|
||||
public class TestMyBikesPageViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_Reserved()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Reserved(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new MyBikeInUseStateInfoProvider(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Location Station 3, still 15 min. reserved."));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_ReservedWithCopriConnect()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_ReservedWithCopriConnect(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new MyBikeInUseStateInfoProvider(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
Assert.That(l_oViewModel.StateText, Is.EqualTo("Code 4asdfA, location Station 3, still 7 min. reserved."));
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Tests base class functionality by using child.
|
||||
/// </summary>
|
||||
///
|
||||
[Test]
|
||||
public void TestStateText_LoggedIn_Booked()
|
||||
{
|
||||
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Booked(
|
||||
(bike, user) => new ShareeBike.ViewModel.Bikes.Bike.BC.BikeViewModel(
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null,
|
||||
bike,
|
||||
user,
|
||||
new MyBikeInUseStateInfoProvider(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
url => { }));
|
||||
|
||||
Assert.That(
|
||||
l_oViewModel.StateText, Is.EqualTo($"Code 4asdfA, location Station 3, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}."));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedClosed
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new BookedClosed(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("End rental"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Open lock"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedDisconnected
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new BookedDisconnected(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Connect lock"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("BookedDisconnected"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNotSupported()
|
||||
{
|
||||
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 pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedDisconnected(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify that nothing happened because request is not supported.
|
||||
Assert.That(subsequent.ButtonText, Is.EqualTo("Connect lock"));
|
||||
Assert.That(subsequent.IsButtonVisible, Is.True);
|
||||
Assert.That(subsequent.LockitButtonText, Is.EqualTo("BookedDisconnected"));
|
||||
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedOpen
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new BookedOpen(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Close lock"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("BookedOpen"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedUnknown
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new BookedUnknown(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Open lock"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Close lock"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestDisposableDisconnected
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new DisposableDisconnected(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Reserve / Rent"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("DisposableDisconnected"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestDisposableOpen
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new DisposableOpen(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Reserve / Rent"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Close lock"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestReservedClosed
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new ReservedClosed(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
public class TestReservedDisconnected
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new ReservedDisconnected(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Start rental"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestReservedOpen
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new ReservedOpen(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Close lock"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Start rental"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestReservedUnknown
|
||||
{
|
||||
/// <summary>
|
||||
/// Test construction of object.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void Testctor()
|
||||
{
|
||||
var handler = new ReservedUnknown(
|
||||
Substitute.For<IBikeInfoMutable>(),
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => Substitute.For<IConnector>(),
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
Substitute.For<ISmartDevice>(),
|
||||
Substitute.For<IViewService>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.That(handler.ButtonText, Is.EqualTo("Close lock"));
|
||||
Assert.That(handler.IsButtonVisible, Is.True);
|
||||
Assert.That(handler.LockitButtonText, Is.EqualTo("Start rental"));
|
||||
Assert.That(handler.IsLockitButtonVisible, Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,207 @@
|
|||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using CloseCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.CloseCommand;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCloseLockActionViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Close lock.
|
||||
/// Final state: Occupied closed, End rental requested
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestCloseLockAndRequestEndRental()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CloseCommand.ICloseCommandListener>();
|
||||
|
||||
var closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.CloseLockAsync(Arg.Any<CloseCommand.ICloseCommandListener>(), Arg.Any<Task>()).Returns(x =>
|
||||
{
|
||||
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.StartingQueryingLocation);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.ClosingLock);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.WaitStopPollingQueryLocation);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.QueryLocationTerminated);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.UpdateLockingState);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await closeLockActionViewModel.CloseLockAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.CloseLock
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
|
||||
//Step.StartingQueryingLocation
|
||||
bikesViewModel.ActionText = "Start query location...";
|
||||
//Step.ClosingLock
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
//Step.WaitStopPollingQueryLocation
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
//Step.UpdateLockingState
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.RentalProcess.StepIndex = 2;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
|
||||
//Ask whether park bike or end rental
|
||||
viewService.DisplayAlert(
|
||||
"Please choose",
|
||||
"Do you want to park the bike to continue riding later or return the bike now and end the rental?",
|
||||
"End rental",
|
||||
"Park bike"
|
||||
);
|
||||
|
||||
closeLockActionViewModel.IsEndRentalRequested = true;
|
||||
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
return;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock.
|
||||
/// Final state: Occupied closed, Park bike requested
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestCloseLockAndRequestParkBike()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CloseCommand.ICloseCommandListener>();
|
||||
|
||||
var closeLockActionViewModel = new CloseLockActionViewModel<BookedOpen>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.CloseLockAsync(Arg.Any<CloseCommand.ICloseCommandListener>(), Arg.Any<Task>()).Returns(x =>
|
||||
{
|
||||
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.StartingQueryingLocation);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.ClosingLock);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.WaitStopPollingQueryLocation);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.QueryLocationTerminated);
|
||||
closeLockActionViewModel.ReportStep(CloseCommand.Step.UpdateLockingState);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await closeLockActionViewModel.CloseLockAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.CloseLock
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
|
||||
//Step.StartingQueryingLocation
|
||||
bikesViewModel.ActionText = "Start query location...";
|
||||
//Step.ClosingLock
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
//Step.WaitStopPollingQueryLocation
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
//Step.UpdateLockingState
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.RentalProcess.StepIndex = 2;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
|
||||
//Ask whether park bike or end rental
|
||||
viewService.DisplayAlert(
|
||||
"Please choose",
|
||||
"Do you want to park the bike to continue riding later or return the bike now and end the rental?",
|
||||
"End rental",
|
||||
"Park bike"
|
||||
);
|
||||
|
||||
closeLockActionViewModel.IsEndRentalRequested = false;
|
||||
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
//Show confirmation
|
||||
viewService.DisplayAlert(
|
||||
"Lock is closed",
|
||||
"Bike is parked. Your chargeable rental continues!",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
return;
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using AuthCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.AuthCommand;
|
||||
using ConnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestConnectLockActionViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Connect lock.
|
||||
/// Final state: Occupied open
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestConnectLock()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<ConnectCommand.IConnectAndGetStateCommandListener>();
|
||||
|
||||
var connectLockActionViewModel = new ConnectLockActionViewModel<BookedDisconnected>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ConnectAsync(Arg.Any<ConnectCommand.IConnectAndGetStateCommandListener>()).Returns(x =>
|
||||
{
|
||||
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
|
||||
connectLockActionViewModel.ReportStep(AuthCommand.Step.Authenticate);
|
||||
connectLockActionViewModel.ReportStep(ConnectCommand.Step.ConnectLock);
|
||||
connectLockActionViewModel.ReportStep(ConnectCommand.Step.GetLockingState);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await connectLockActionViewModel.ConnectLockAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
//Auth
|
||||
bikesViewModel.ActionText = "Calculate authentication keys...";
|
||||
//Connect lock & Get State
|
||||
bikesViewModel.ActionText = "Connecting lock...";
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
return;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using OpenCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.OpenCommand;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.BluetoothLock
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestOpenLockActionViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Open lock.
|
||||
/// Final state: Occupied open
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestOpenLock()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<OpenCommand.IOpenCommandListener>();
|
||||
|
||||
var openLockActionViewModel = new OpenLockActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.OpenLockAsync(Arg.Any<OpenCommand.IOpenCommandListener>(), Arg.Any<Task>()).Returns(x =>
|
||||
{
|
||||
// Add calls to ReportStep which IBikeInfoMutable implementation would do.
|
||||
openLockActionViewModel.ReportStep(OpenCommand.Step.OpeningLock);
|
||||
openLockActionViewModel.ReportStep(OpenCommand.Step.GetLockInfos);
|
||||
openLockActionViewModel.ReportStep(OpenCommand.Step.UpdateLockingState);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await openLockActionViewModel.OpenLockAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.OpenLock
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
|
||||
//ClosingLock & GetLockInfos
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
//UpdateLockingState
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
return;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,194 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using SharedBusinessLogic.Tests.Framework.Model.Services.Geolocation;
|
||||
using SharedBusinessLogic.Tests.Framework.Services.BluetoothLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.Bike.BluetoothLock
|
||||
{
|
||||
/// <summary>
|
||||
/// Moved to SharedBusinessLogic.Tests (.Net Core)
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class TestRequestHandlerFactory
|
||||
{
|
||||
[Test]
|
||||
public void TestCreate()
|
||||
{
|
||||
// Verify handler for disposable bike.
|
||||
var bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "12"),
|
||||
"My Station Name");
|
||||
Assert.That(bike.State.Value, Is.EqualTo(InUseStateEnum.Disposable));
|
||||
Assert.That(bike.LockInfo.State, Is.EqualTo(LockingState.UnknownDisconnected));
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */ ,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(DisposableDisconnected)));
|
||||
|
||||
// Verify handler for requested bike with state unknown.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id */, new Guid(), /*K User*/ null, /*K Admin*/ null, /*K Seed*/ null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
|
||||
"My Station Name");
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(ReservedDisconnected)));
|
||||
|
||||
// Verify handler for requested bike with state closed.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
|
||||
"My Station Name");
|
||||
bike.LockInfo.State = LockingState.Closed;
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(ReservedClosed)));
|
||||
|
||||
// Verify handler for requested bike with state open.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null /* user key */, null, null, new DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>()),
|
||||
"My Station Name");
|
||||
bike.LockInfo.State = LockingState.Open;
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(ReservedOpen)));
|
||||
|
||||
// Verify handler for booked bike with state closed.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
|
||||
"My Station Name");
|
||||
bike.LockInfo.State = LockingState.Closed;
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(BookedClosed)));
|
||||
|
||||
// Verify handler for booked bike with state open.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
|
||||
"My Station Name");
|
||||
bike.LockInfo.State = LockingState.Open;
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(BookedOpen)));
|
||||
|
||||
// Verify handler for booked bike with state unknown.
|
||||
bike = new BikeInfoMutable(
|
||||
Substitute.For<IGeolocationService>(),
|
||||
Substitute.For<ILocksService>(),
|
||||
() => false /* not connected */,
|
||||
(_) => Substitute.For<IConnector>(),
|
||||
() => Substitute.For<IPollingUpdateTaskManager>(),
|
||||
new BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("22", LockModel.ILockIt, WheelType.Mono, TypeOfBike.Allround), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null /*operator uri*/, null, false, new List<string>()),
|
||||
"My Station Name");
|
||||
|
||||
Assert.That(
|
||||
RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => false, // isConnectedDelegate
|
||||
(connected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // LockService
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null /* viewService */,
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
Substitute.For<IUser>()).GetType(), Is.EqualTo(typeof(BookedDisconnected)));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,221 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Repository.Exception;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedClosed
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Try to open lock.
|
||||
/// Final state: Bike remains locked and stays booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLockOpenLockAsyncFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.OpenLockAsync(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // State remains booked because opening failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedClosed"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try to open lock.
|
||||
/// Final state: Bike remains locked and stays booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLockOpenLockAsyncFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.OpenLockAsync(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // State remains booked because opening failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Lock could not be opened!",
|
||||
"Some error",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedClosed"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Open lock.
|
||||
/// Final state: Lock is opened and bike remains booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLock()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // After opening, lock state is open.
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // After Booking and opening, state is booked.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedOpen"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Repository.Exception;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBookedOpen
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Try to open lock.
|
||||
/// Final state: Bike remains locked and stays booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLockOpenLockAsyncFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.OpenLockAsync(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // State remains booked because opening failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedClosed"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try to open lock.
|
||||
/// Final state: Bike remains locked and stays booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLockOpenLockAsyncFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.OpenLockAsync(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // State remains booked because opening failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Lock could not be opened!",
|
||||
"Some error",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedClosed"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Open lock.
|
||||
/// Final state: Lock is opened and bike remains booked.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestOpenLock()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new BookedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // After opening, lock state is open.
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // After Booking and opening, state is booked.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Lock is opening. Please wait until it is completely open.";
|
||||
connector.Command.OpenLockAsync(bike); // Booking must be performed
|
||||
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedOpen"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,664 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Repository.Exception;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||
{
|
||||
public class TestDisposableClosed
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Start booking and cancel.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseCancel()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Rent bike Nr. 0 and open lock?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(false)); // User chooes "No"
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Rent bike Nr. 0 and open lock?",
|
||||
"Yes",
|
||||
"No");
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book bike and release from station.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseBookAndOpenAyncFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.BookAndOpenAync(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // State remains available because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book bike and release from station.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseBookAndOpenAyncFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.BookAndOpenAync(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // State remains available because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Bike could not be rented!",
|
||||
"Some error",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Book bike and release from station.
|
||||
/// Final state: Bike is booked and released from station.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndRelease()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // After Booking and opening, lock state is open.
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // After Booking and opening, state is booked.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedOpen"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Cancel reserving.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveCancel()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(false)); // User chooes "No"
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No");
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book reserve bike.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveDoReserveFailsBookingDeclinedException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.DoReserve(bike).Returns(x => throw new BookingDeclinedException(4));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // State remains available because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Hint",
|
||||
"A reservation of bike Nr. 0 was rejected because the maximum allowed number of 4 reservations/rentals had already been made.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book reserve bike.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveDoReserveFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.DoReserve(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // State remains available because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book reserve bike.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveDoReserveFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Locking state does not change.
|
||||
|
||||
connector.Command.DoReserve(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // State remains available because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Bike could not be reserved!",
|
||||
"Some error",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve bike.
|
||||
/// Final state: Bike is booked and released from station.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserve()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Reserve bike Nr. 0 free of charge for 15 min?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // After Booking and opening, lock state is open.
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // After Booking and opening, lock state is open.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedOpen"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,204 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestFeedbackPending
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Give feedback but submission fails.
|
||||
/// Final state: Feedback is pending.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGiveFeedbackDoSubmitFeedbackFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new FeedbackPending(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
connector.Command.DoSubmitFeedback(
|
||||
Arg.Any<ShareeBike.Model.Connector.IUserFeedback>(),
|
||||
Arg.Any<Uri>()).Returns(x => throw new Exception("Context info", new Exception("Tst")));
|
||||
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
viewService.DisplayUserFeedbackPopup(Arg.Any<IBatteryMutable>());
|
||||
bikesViewModel.ActionText = "Submitting feedback...";
|
||||
connector.Command.DoSubmitFeedback(Arg.Any<ShareeBike.Model.Connector.IUserFeedback>(), Arg.Any<Uri>()); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Submitting feedback failed!",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("FeedbackPending"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Give feedback"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Give feedback.
|
||||
/// Final state: Feedback is pending.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGiveFeedback()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new FeedbackPending(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
viewService.DisplayUserFeedbackPopup(Arg.Any<IBatteryMutable>());
|
||||
bikesViewModel.ActionText = "Submitting feedback...";
|
||||
connector.Command.DoSubmitFeedback(Arg.Any<ShareeBike.Model.Connector.IUserFeedback>(), Arg.Any<Uri>()); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("FeedbackPending"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Give feedback"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Give feedback.
|
||||
/// Final state: Feedback is pending.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestGiveFeedbackAndQuerry()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new FeedbackPending(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.BookingFinishedModel.MiniSurvey.Questions.Count.Returns(1);
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
viewService.DisplayUserFeedbackPopup(Arg.Any<IBatteryMutable>());
|
||||
bikesViewModel.ActionText = "Submitting feedback...";
|
||||
connector.Command.DoSubmitFeedback(Arg.Any<ShareeBike.Model.Connector.IUserFeedback>(), Arg.Any<Uri>()); // Booking must be performed
|
||||
viewService.PushModalAsync(ViewTypes.MiniSurvey);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("FeedbackPending"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Give feedback"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,639 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Repository.Exception;
|
||||
using ShareeBike.Repository.Response;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock.RequestHandler
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestReservedClosed
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Cancel reservation.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCancelReservationCancel()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(false)); // User chooes "No"
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No");
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCancelReservationDoCancelReservationInvalidAuthorizationResponseException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new InvalidAuthorizationResponseException(
|
||||
"otto@mustermann.de", JsonConvert.DeserializeObject<ResponseBase>(@"{}")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved); // Locking state does not change.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"Your session has expired. Please login new and try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCancelReservationDoCancelReservationFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved); // Locking state does not change.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try cancel reservation.
|
||||
/// Final state: Bike remains reserved.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCancelReservationDoCancelReservationFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved); // Locking state does not change.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike); // Cancel reservation must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"Some error",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Cancel reservation.
|
||||
/// Final state: Bike is available again.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCancelReservation()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Cancel reservation for bike Nr. 0?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable); // Reservation gets canceled.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike); // Cancel reservation must be performed
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Reserve bike"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Cancel booking.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseCancel()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Rent bike Nr. 0 and open lock?",
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(false)); // User chooes "No"
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
"Rent bike Nr. 0 and open lock?",
|
||||
"Yes",
|
||||
"No");
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book bike and release from station.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseBookAndOpenAyncFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.BookAndOpenAync(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved); // State remains reserved because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Try book bike and release from station.
|
||||
/// Final state: Bike is disposable.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndReleaseBookAndOpenAyncFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.BookAndOpenAync(bike).Returns(x => throw new Exception("Some error", new Exception("Inner exception")));
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved); // State remains reserved because booking request failed.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Bike could not be rented!",
|
||||
"Some error",
|
||||
String.Empty,
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("Cancel reservation"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.True);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Start rental & Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Book bike and release from station.
|
||||
/// Final state: Bike is booked and released from station.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookAndRelease()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedClosed(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty,
|
||||
string.Format("Rent bike {0} and open lock?", "Nr. 0"),
|
||||
"Yes",
|
||||
"No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // After Booking and opening, lock state is open.
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked); // After Booking and opening, state is booked.
|
||||
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.BookAndOpenAync(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state
|
||||
Assert.That(
|
||||
subsequent.ButtonText,
|
||||
Is.EqualTo("BookedOpen"));
|
||||
Assert.That(
|
||||
subsequent.IsButtonVisible,
|
||||
Is.False);
|
||||
Assert.That(
|
||||
subsequent.LockitButtonText,
|
||||
Is.EqualTo("Open lock"));
|
||||
Assert.That(
|
||||
subsequent.IsLockitButtonVisible,
|
||||
Is.True);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.CopriLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.CopriLock.RequestHandler;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike.CopriLock
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestReqeustHandlerFactory
|
||||
{
|
||||
[Test]
|
||||
public void TestCreateDisposable()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var smartDevice = Substitute.For<ISmartDevice>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Disposable);
|
||||
|
||||
var requestHandler = RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => true /*isConnectedDelegate*/,
|
||||
(isconnected) => connector,
|
||||
() => pollingManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
Assert.That(
|
||||
requestHandler.GetType(),
|
||||
Is.EqualTo(typeof(DisposableClosed)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateReserved()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var smartDevice = Substitute.For<ISmartDevice>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Reserved);
|
||||
|
||||
var requestHandler = RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => true /*isConnectedDelegate*/,
|
||||
(isconnected) => connector,
|
||||
() => pollingManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
Assert.That(
|
||||
requestHandler.GetType(),
|
||||
Is.EqualTo(typeof(ReservedClosed)));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateBooked()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var smartDevice = Substitute.For<ISmartDevice>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.Booked);
|
||||
|
||||
foreach (LockingState state in Enum.GetValues(typeof(LockingState)))
|
||||
{
|
||||
bike.LockInfo.State.Returns(state);
|
||||
|
||||
var requestHandler = RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => true /*isConnectedDelegate*/,
|
||||
(isconnected) => connector,
|
||||
() => pollingManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
Assert.That(
|
||||
requestHandler.GetType(),
|
||||
Is.EqualTo(state == LockingState.Closed
|
||||
? typeof(BookedClosed)
|
||||
: typeof(BookedOpen)));
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateFeedbackPending()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var smartDevice = Substitute.For<ISmartDevice>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
bike.State.Value.Returns(ShareeBike.Model.State.InUseStateEnum.FeedbackPending);
|
||||
|
||||
foreach (LockingState state in Enum.GetValues(typeof(LockingState)))
|
||||
{
|
||||
bike.LockInfo.State.Returns(state);
|
||||
|
||||
var requestHandler = RequestHandlerFactory.Create(
|
||||
bike,
|
||||
() => true /*isConnectedDelegate*/,
|
||||
(isconnected) => connector,
|
||||
() => pollingManager,
|
||||
smartDevice,
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
Assert.That(
|
||||
requestHandler.GetType(),
|
||||
Is.EqualTo(typeof(FeedbackPending)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
using NUnit.Framework;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBikeViewModelBase
|
||||
{
|
||||
[Test]
|
||||
public void TestGetUrl()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelBase.GetUrlFirstOrDefault(@"Mit der Mietrad Anmietung wird folgender Betreiber <a href='https://shareeapp-fr01.copri.eu/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)."),
|
||||
Is.EqualTo(@"https://shareeapp-fr01.copri.eu/site/agb.html"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetUrlNoProtocol()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelBase.GetUrlFirstOrDefault(@"Mit der Mietrad Anmietung wird folgender Betreiber <a href='shareeapp-fr01.copri.eu/site/agb.html' target='_blank'>AGB</a> zugestimmt (als Demo sharee AGB)."),
|
||||
Is.EqualTo(""));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestGetUrlNull()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelBase.GetUrlFirstOrDefault(null),
|
||||
Is.EqualTo(""));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
using System;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using SharedBusinessLogic.Tests.Framework.Model.Services.Geolocation;
|
||||
using SharedBusinessLogic.Tests.Framework.Services.BluetoothLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BC;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.Device;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.Fixtures.ObjectTests.ViewModel
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestBikeViewModelFactory
|
||||
{
|
||||
private class BikeInfoMutableUnsupported : BikeInfoMutable
|
||||
{
|
||||
/// <summary> Constructs a bike object from source. </summary>
|
||||
public BikeInfoMutableUnsupported(IBikeInfo bike, string stationName) : base(
|
||||
bike != null
|
||||
? bike.Bike
|
||||
: throw new ArgumentNullException(nameof(bike)),
|
||||
bike.Drive,
|
||||
bike.DataSource,
|
||||
bike.IsDemo,
|
||||
bike.Group,
|
||||
bike.StationId,
|
||||
stationName,
|
||||
bike.OperatorUri,
|
||||
bike.TariffDescription,
|
||||
null /* date time provider */,
|
||||
bike.State)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateBluetoothLock()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelFactory.Create(
|
||||
() => false, // Is connected delegate,
|
||||
(isconnected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // lock service
|
||||
(index) => { }, // bikeRemoveDelegate
|
||||
null, // viewUpdateManager
|
||||
Substitute.For<ISmartDevice>(),
|
||||
null, // viewService
|
||||
new ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.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("42", LockModel.ILockIt), new DriveMutable(), DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"),
|
||||
Substitute.For<IUser>(), // user
|
||||
null /*ViewContext*/,
|
||||
Substitute.For<IInUseStateInfoProvider>(),
|
||||
Substitute.For<IBikesViewModel>(),
|
||||
url => { }).GetType(), Is.EqualTo(typeof(ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel))); // stateInfoProvider
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateCopri()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelFactory.Create(
|
||||
() => false, // Is connected delegate,
|
||||
(isconnected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // lock service
|
||||
(index) => { }, // bikeRemoveDelegate
|
||||
null, // viewUpdateManager
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null, // viewService
|
||||
new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfoMutable(new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("42", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, "17", new ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockInfo.Builder { State = ShareeBike.Model.Bikes.BikeInfoNS.CopriLock.LockingState.Closed }.Build()), "My Station Name"),
|
||||
NSubstitute.Substitute.For<IUser>(), // user
|
||||
new ViewContext(PageContext.BikesAtStation, "FR1012"), // Context does not matter for this test.
|
||||
NSubstitute.Substitute.For<IInUseStateInfoProvider>(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { }).GetType(), Is.EqualTo(typeof(ShareeBike.ViewModel.Bikes.Bike.CopriLock.BikeViewModel))); // stateInfoProvider
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCreateUnsupported()
|
||||
{
|
||||
Assert.That(
|
||||
BikeViewModelFactory.Create(
|
||||
() => false, // Is connected delegate,
|
||||
(isconnected) => null, // connectorFactory
|
||||
new GeolocationMock(), // geolocation
|
||||
new LocksServiceMock(), // lock service
|
||||
(index) => { }, // bikeRemoveDelegate
|
||||
null, // viewUpdateManager
|
||||
NSubstitute.Substitute.For<ISmartDevice>(),
|
||||
null, // viewService
|
||||
new BikeInfoMutableUnsupported(new ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.BikeInfo(new ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Bike("42", ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.LockModel.ILockIt), new DriveMutable(), DataSource.Copri, 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42"), "My Station Name"),
|
||||
NSubstitute.Substitute.For<IUser>(), // user
|
||||
new ViewContext(PageContext.BikesAtStation, "FR1012"), // Context does not matter for this test.
|
||||
NSubstitute.Substitute.For<IInUseStateInfoProvider>(),
|
||||
NSubstitute.Substitute.For<IBikesViewModel>(),
|
||||
url => { }),
|
||||
Is.Null);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,229 @@
|
|||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using CancelReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.CancelReservationCommand;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
using ShareeBike.Model.State;
|
||||
using NSubstitute.Core.Arguments;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestCancelReservationActionViewModel
|
||||
{
|
||||
[Test]
|
||||
public async Task TestCancelReservation()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CancelReservationCommand.ICancelReservationCommandListener>();
|
||||
|
||||
var cancelReservationActionViewModel = new CancelReservationActionViewModel<ReservedClosed>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
bike.CancelReservationAsync(Arg.Any<CancelReservationCommand.ICancelReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
cancelReservationActionViewModel.ReportStep(CancelReservationCommand.Step.CancelReservation);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.LockInfo.State.Returns(LockingState.Closed);
|
||||
|
||||
bike.DisconnectAsync(Arg.Any<DisconnectCommand.IDisconnectCommandListener>()).Returns(x =>
|
||||
{
|
||||
cancelReservationActionViewModel.ReportStep(DisconnectCommand.Step.DisconnectLock);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await cancelReservationActionViewModel.CancelReservationAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestCancelReservationException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CancelReservationCommand.ICancelReservationCommandListener>();
|
||||
|
||||
var cancelReservationActionViewModel = new CancelReservationActionViewModel<ReservedClosed>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
bike.CancelReservationAsync(Arg.Any<CancelReservationCommand.ICancelReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
cancelReservationActionViewModel.ReportStep(CancelReservationCommand.Step.CancelReservation);
|
||||
cancelReservationActionViewModel.ReportStateAsync(CancelReservationCommand.State.GeneralCancelReservationError, "details").Wait();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await cancelReservationActionViewModel.CancelReservationAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"details",
|
||||
"Please try again.",
|
||||
"OK");
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestCancelReservationNoWebException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CancelReservationCommand.ICancelReservationCommandListener>();
|
||||
|
||||
var cancelReservationActionViewModel = new CancelReservationActionViewModel<ReservedClosed>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
bike.CancelReservationAsync(Arg.Any<CancelReservationCommand.ICancelReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
cancelReservationActionViewModel.ReportStep(CancelReservationCommand.Step.CancelReservation);
|
||||
cancelReservationActionViewModel.ReportStateAsync(CancelReservationCommand.State.WebConnectFailed, "details").Wait();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await cancelReservationActionViewModel.CancelReservationAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestCancelReservationInvalidResponseException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<CancelReservationCommand.ICancelReservationCommandListener>();
|
||||
|
||||
var cancelReservationActionViewModel = new CancelReservationActionViewModel<ReservedClosed>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
bike.CancelReservationAsync(Arg.Any<CancelReservationCommand.ICancelReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
cancelReservationActionViewModel.ReportStep(CancelReservationCommand.Step.CancelReservation);
|
||||
cancelReservationActionViewModel.ReportStateAsync(CancelReservationCommand.State.InvalidResponse, "details").Wait();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await cancelReservationActionViewModel.CancelReservationAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"Your session has expired. Please login new and try again.",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,463 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NSubstitute.ExceptionExtensions;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Model.User;
|
||||
using ShareeBike.Repository.Request;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.Services.Geolocation;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using EndRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.EndRentalCommand;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
using ShareeBike.Repository.Exception;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestEndRentalActionViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Initial state: No LastGeolocation from CloseLock, Lock currently in reach
|
||||
/// Final state: Disposable closed
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnLockInReach()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<EndRentalCommand.IEndRentalCommandListener>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
returnBikeActionViewModel.ReportStep(DisconnectCommand.Step.DisconnectLock);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Initial state: No LastGeolocation from CloseLock, Lock currently out of reach
|
||||
/// Final state: Booked, lock state unknown.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnNoGPSData()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Throws((x) =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.NoGPSData, "").Wait();
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
NoGPSDataException.IsNoGPSData("exception.", out NoGPSDataException noGPSDataException);
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw noGPSDataException);
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
//viewService.DisplayAlert(
|
||||
// "Rental could not be terminated!",
|
||||
// "We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!\r\n\r\nApproach the bike lock, turn on Bluetooth and Location services and try again.",
|
||||
// "OK");
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.That(
|
||||
bike.LockInfo.State,
|
||||
Is.EqualTo(LockingState.UnknownDisconnected));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnReturnFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(async x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
await returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.WebConnectFailed, "");
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
//await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
viewService.DisplayAlert(
|
||||
"Rental could not be terminated!",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnReturnFailsNotAtStationException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(async x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
await returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.NotAtStation, "");
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
//viewService.DisplayAlert(
|
||||
// "Rental could not be terminated!",
|
||||
// "We could not assign the bike to any station. For this we need your location information while you are standing right next to the bike. Only then your rental can be terminated!\r\n\r\nApproach the bike lock, turn on Bluetooth and Location services and try again.",
|
||||
// "OK"
|
||||
//);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Initial state: Copri reports that no GPS data available
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnReturnFailsNoGPSDataException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(async x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
await returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.NoGPSData, "");
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
viewService.DisplayAlert(
|
||||
"Rental could not be terminated!",
|
||||
"End rental at an unknown location is not possible.\r\nRental can be ended if\r\n- location information is available when closing lock\r\n- bike is in reach and location information is available when pressing button \"End rental\"",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnReturnFailsResponseException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(async x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
await returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.ResponseException, "");
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
viewService.DisplayAlert(
|
||||
"Rental could not be terminated!",
|
||||
"Connection error, invalid server response.",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: End rental.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReturnReturnFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
|
||||
var returnBikeActionViewModel = new EndRentalActionViewModel<BookedClosed>(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnected) => connector,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.ReturnBikeAsync(Arg.Any<EndRentalCommand.IEndRentalCommandListener>()).Returns(async x =>
|
||||
{
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.GetLocation);
|
||||
returnBikeActionViewModel.ReportStep(EndRentalCommand.Step.ReturnBike);
|
||||
await returnBikeActionViewModel.ReportStateAsync(EndRentalCommand.State.GeneralEndRentalError, "");
|
||||
throw new Exception();
|
||||
});
|
||||
|
||||
connector.Command.DoReturn(bike, Arg.Any<LocationDto>()).Returns<BookingFinishedModel>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Request handler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Closed); // Request handler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
await returnBikeActionViewModel.EndRentalAsync();
|
||||
|
||||
//await locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.ActionText = "Query location...";
|
||||
bikesViewModel.ActionText = "Ending rental...";
|
||||
viewService.DisplayAlert(
|
||||
"Rental could not be terminated!",
|
||||
"Please try again.",
|
||||
"OK"
|
||||
);
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,342 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using NSubstitute;
|
||||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS;
|
||||
using ShareeBike.Model.Connector;
|
||||
using ShareeBike.Model.State;
|
||||
using ShareeBike.Services.BluetoothLock;
|
||||
using ShareeBike.View;
|
||||
using ShareeBike.ViewModel;
|
||||
using ShareeBike.ViewModel.Bikes;
|
||||
using ShareeBike.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
|
||||
using StartReservationCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartReservationCommand;
|
||||
using ConnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.ConnectAndGetStateCommand;
|
||||
using StartRentalCommand = ShareeBike.Model.Bikes.BikeInfoNS.BikeNS.Command.StartRentalCommand;
|
||||
using DisconnectCommand = ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock.Command.DisconnectCommand;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestStartReservationOrRentalActionViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Use case: Reserve / Rent.
|
||||
/// Initial state: Disposable UnknownDisconnected, Lock currently in reach
|
||||
/// Final state: Booked Closed
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReserveLockInReachRent()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<StartReservationCommand.IStartReservationCommandListener>();
|
||||
|
||||
var startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableDisconnected>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.AaRideType.Returns(AaRideType.NoAaRide);
|
||||
|
||||
bike.ReserveBikeAsync(Arg.Any<StartReservationCommand.IStartReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(StartReservationCommand.Step.ReserveBike);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.ConnectAsync(Arg.Any<ConnectCommand.IConnectAndGetStateCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.ConnectLock);
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.GetLockingState);
|
||||
bike.LockInfo.State.Returns(LockingState.Closed);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
viewService.DisplayAlert(
|
||||
"Rent bike?",
|
||||
"Do you want to rent the bike and open the lock?",
|
||||
"Rent bike & open lock",
|
||||
"Cancel")
|
||||
.Returns(Task.FromResult(true));
|
||||
|
||||
bike.RentBikeAsync(Arg.Any<StartRentalCommand.IStartRentalCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(StartRentalCommand.Step.RentBike);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
bike.LockInfo.State.Returns(LockingState.Closed);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.StartReservationOrRental
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.RentalProcess.StepIndex = 2;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
bikesViewModel.ActionText = "Connecting lock...";
|
||||
viewService.DisplayAlert(
|
||||
"Rent bike?",
|
||||
"Do you want to rent the bike and open the lock?",
|
||||
"Rent bike & open lock",
|
||||
"Cancel");
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
startReservationOrRentalActionViewModel.ContinueWithOpenLock = true;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve / Rent.
|
||||
/// Initial state: Disposable UnknownDisconnected, Lock out of reach
|
||||
/// Final state: Reserved UnknownDisconnected
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReserveLockOutOfReach()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<StartReservationCommand.IStartReservationCommandListener>();
|
||||
|
||||
var startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableDisconnected>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.AaRideType.Returns(AaRideType.NoAaRide);
|
||||
|
||||
bike.ReserveBikeAsync(Arg.Any<StartReservationCommand.IStartReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(StartReservationCommand.Step.ReserveBike);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.ConnectAsync(Arg.Any<ConnectCommand.IConnectAndGetStateCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.ConnectLock);
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.GetLockingState);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.StartReservationOrRental
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.RentalProcess.StepIndex = 2;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
bikesViewModel.ActionText = "Connecting lock...";
|
||||
startReservationOrRentalActionViewModel.ContinueWithOpenLock = false;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
viewService.DisplayAlert(
|
||||
"Bike is reserved",
|
||||
"If you do not rent the bike within the next few minutes, your reservation will expire.",
|
||||
"OK");
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve / Rent.
|
||||
/// Initial state: Disposable UnknownDisconnected, Lock currently in reach
|
||||
/// Final state: Reserved UnknownDisconnected
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReserveLockInReachCancel()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<StartReservationCommand.IStartReservationCommandListener>();
|
||||
|
||||
var startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableDisconnected>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.AaRideType.Returns(AaRideType.NoAaRide);
|
||||
|
||||
bike.ReserveBikeAsync(Arg.Any<StartReservationCommand.IStartReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(StartReservationCommand.Step.ReserveBike);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
bike.ConnectAsync(Arg.Any<ConnectCommand.IConnectAndGetStateCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.ConnectLock);
|
||||
startReservationOrRentalActionViewModel.ReportStep(ConnectCommand.Step.GetLockingState);
|
||||
bike.LockInfo.State.Returns(LockingState.Closed);
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
viewService.DisplayAlert(
|
||||
"Rent bike?",
|
||||
"Do you want to rent the bike and open the lock?",
|
||||
"Rent bike & open lock",
|
||||
"Cancel")
|
||||
.Returns(Task.FromResult(false));
|
||||
|
||||
await startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.StartReservationOrRental
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
|
||||
bikesViewModel.RentalProcess.StepIndex = 2;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.None;
|
||||
bikesViewModel.ActionText = "Connecting lock...";
|
||||
viewService.DisplayAlert(
|
||||
"Rent bike?",
|
||||
"Do you want to rent the bike and open the lock?",
|
||||
"Rent bike & open lock",
|
||||
"Cancel");
|
||||
startReservationOrRentalActionViewModel.ContinueWithOpenLock = false;
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Succeeded;
|
||||
viewService.DisplayAlert(
|
||||
"Bike is reserved",
|
||||
"If you do not rent the bike within the next few minutes, your reservation will expire.",
|
||||
"OK");
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve / Rent.
|
||||
/// Initial state: Disposable UnknownDisconnected
|
||||
/// Final state: Disposable UnknownDisconnected
|
||||
/// </summary>
|
||||
[Test]
|
||||
public async Task TestReserveException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var listener = Substitute.For<StartReservationCommand.IStartReservationCommandListener>();
|
||||
|
||||
var startReservationOrRentalActionViewModel = new StartReservationOrRentalActionViewModel<DisposableDisconnected>(
|
||||
bike,
|
||||
() => pollingManager,
|
||||
viewService,
|
||||
bikesViewModel);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
bike.AaRideType.Returns(AaRideType.NoAaRide);
|
||||
|
||||
bike.ReserveBikeAsync(Arg.Any<StartReservationCommand.IStartReservationCommandListener>()).Returns(x =>
|
||||
{
|
||||
startReservationOrRentalActionViewModel.ReportStep(StartReservationCommand.Step.ReserveBike);
|
||||
startReservationOrRentalActionViewModel.ReportStateAsync(StartReservationCommand.State.GeneralStartReservationError, "details").Wait();
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
|
||||
await startReservationOrRentalActionViewModel.StartReservationOrRentalAsync();
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
|
||||
bikesViewModel.StartRentalProcess(Arg.Is<IRentalProcessViewModel>(
|
||||
x => x.BikeId == "0"
|
||||
&& x.State == CurrentRentalProcess.StartReservationOrRental
|
||||
&& x.StepIndex == 1
|
||||
&& x.Result == CurrentStepStatus.None));
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
bikesViewModel.RentalProcess.Result = CurrentStepStatus.Failed;
|
||||
bikesViewModel.ActionText = String.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Bike could not be reserved!",
|
||||
"details",
|
||||
"Please try again.",
|
||||
"OK");
|
||||
startReservationOrRentalActionViewModel.ContinueWithOpenLock = false;
|
||||
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.RentalProcess.State = CurrentRentalProcess.None;
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,223 @@
|
|||
using NUnit.Framework;
|
||||
using ShareeBike.Model.Bikes.BikeInfoNS;
|
||||
using ShareeBike.ViewModel.Bikes.Bike;
|
||||
|
||||
namespace SharedBusinessLogic.Tests.ViewModel.Bikes.Bike
|
||||
{
|
||||
[TestFixture]
|
||||
public class TestTariffDescriptionViewModel
|
||||
{
|
||||
[Test]
|
||||
public void TestCtor()
|
||||
{
|
||||
var model = new RentalDescription
|
||||
{
|
||||
Name = "Fancy Tarif",
|
||||
Id = 47,
|
||||
TariffEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.TariffElement>
|
||||
{
|
||||
{ "23", new RentalDescription.TariffElement { Value = "Max Gebühr", Description = "9.00 € / Tag"} },
|
||||
{ "24", new RentalDescription.TariffElement { Value = "Gratis Mietzeit", Description = "30 Min / Tag"} },
|
||||
},
|
||||
InfoEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.InfoElement>
|
||||
{
|
||||
{ "14", new RentalDescription.InfoElement { Key = "AGB" , Value = "Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt" } },
|
||||
}
|
||||
};
|
||||
|
||||
var viewModel = new TariffDescriptionViewModel(model);
|
||||
|
||||
Assert.That(
|
||||
viewModel.Name,
|
||||
Is.EqualTo("Fancy Tarif"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TariffEntries.Count,
|
||||
Is.EqualTo(2));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntries.Count,
|
||||
Is.EqualTo(1));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Value,
|
||||
Is.EqualTo("Max Gebühr"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Description,
|
||||
Is.EqualTo("9.00 € / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Value,
|
||||
Is.EqualTo("Gratis Mietzeit"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Description,
|
||||
Is.EqualTo("30 Min / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Value,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Description,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TrackingInfoText,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry1,
|
||||
Is.EqualTo("Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry2,
|
||||
Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCtorTracking()
|
||||
{
|
||||
var model = new RentalDescription
|
||||
{
|
||||
Name = "Fancy Tarif",
|
||||
Id = 47,
|
||||
TariffEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.TariffElement>
|
||||
{
|
||||
{ "23", new RentalDescription.TariffElement { Value = "Max Gebühr", Description = "9.00 € / Tag"} },
|
||||
{ "24", new RentalDescription.TariffElement { Value = "Gratis Mietzeit", Description = "30 Min / Tag"} },
|
||||
},
|
||||
InfoEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.InfoElement>
|
||||
{
|
||||
{ "14", new RentalDescription.InfoElement { Key = "AGB" , Value = "Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt" } },
|
||||
{ "15", new RentalDescription.InfoElement { Key = "Tracking", Value = "Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!" } },
|
||||
}
|
||||
};
|
||||
|
||||
var viewModel = new TariffDescriptionViewModel(model);
|
||||
|
||||
Assert.That(
|
||||
viewModel.Name,
|
||||
Is.EqualTo("Fancy Tarif"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TariffEntries.Count,
|
||||
Is.EqualTo(2));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntries.Count,
|
||||
Is.EqualTo(1));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Value,
|
||||
Is.EqualTo("Max Gebühr"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Description,
|
||||
Is.EqualTo("9.00 € / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Value,
|
||||
Is.EqualTo("Gratis Mietzeit"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Description,
|
||||
Is.EqualTo("30 Min / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Value,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Description,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TrackingInfoText,
|
||||
Is.EqualTo("Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry1,
|
||||
Is.EqualTo("Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry2,
|
||||
Is.Empty);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestCtorAaFahrten()
|
||||
{
|
||||
var model = new RentalDescription
|
||||
{
|
||||
Name = "Fancy Tarif",
|
||||
Id = 47,
|
||||
TariffEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.TariffElement>
|
||||
{
|
||||
{ "23", new RentalDescription.TariffElement { Value = "Max Gebühr", Description = "9.00 € / Tag"} },
|
||||
{ "24", new RentalDescription.TariffElement { Value = "Gratis Mietzeit", Description = "30 Min / Tag"} },
|
||||
},
|
||||
InfoEntries = new System.Collections.Generic.Dictionary<string, RentalDescription.InfoElement>
|
||||
{
|
||||
{ "14", new RentalDescription.InfoElement { Key = "AGB" , Value = "Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt" } },
|
||||
{ "15", new RentalDescription.InfoElement { Key = "AAFahrten", Value = "Testtext aa Fahrten." } },
|
||||
}
|
||||
};
|
||||
|
||||
var viewModel = new TariffDescriptionViewModel(model);
|
||||
|
||||
Assert.That(
|
||||
viewModel.Name,
|
||||
Is.EqualTo("Fancy Tarif"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TariffEntries.Count,
|
||||
Is.EqualTo(2));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntries.Count,
|
||||
Is.EqualTo(1));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Value,
|
||||
Is.EqualTo("Max Gebühr"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry1.Description,
|
||||
Is.EqualTo("9.00 € / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Value,
|
||||
Is.EqualTo("Gratis Mietzeit"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry2.Description,
|
||||
Is.EqualTo("30 Min / Tag"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Value,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TarifEntry3.Description,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.TrackingInfoText,
|
||||
Is.Empty);
|
||||
|
||||
Assert.That(
|
||||
viewModel.RideTypeText,
|
||||
Is.EqualTo("Testtext aa Fahrten."));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry1,
|
||||
Is.EqualTo("Mit der Mietrad Anmietung wird folgender Betreiber <a href='$varenv->{wwwhost}/site/agb.html' target='_blank'>AGB</a> zugestimmt"));
|
||||
|
||||
Assert.That(
|
||||
viewModel.InfoEntry2,
|
||||
Is.Empty);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue