Legacy testing lib added..

This commit is contained in:
Oliver Hauff 2021-07-12 21:31:46 +02:00
parent 0167fc321f
commit 47ed05837e
118 changed files with 17505 additions and 0 deletions

View file

@ -0,0 +1,237 @@
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using TestTINKLib.Mocks.Connector;
using TestTINKLib.Mocks.Device;
using TestTINKLib.Mocks.Services;
using TestTINKLib.Model.User.Account;
using TINK.Model;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.View;
using TINK.Model.Services.CopriApi;
using TINK.Repository;
using static TINK.Repository.CopriCallsMemory;
using TINK.ViewModel.Map;
using TINK.ViewModel.Settings;
using TINK.ViewModel.Account;
using TINK.Services;
using TINK.Model.Services.Geolocation;
using NSubstitute;
namespace TestTINKLib.Fixtures.ObjectTests.Account
{
public class TestAccountPageViewModel
{
[Test]
public void TestConstruct_NotLoggedIn()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
viewService);
Assert.AreEqual("No user logged in.", settingsPageViewModel.LoggedInInfo);
Assert.IsFalse(settingsPageViewModel.IsBookingStateInfoVisible, "No user logged in.");
Assert.AreEqual(string.Empty, settingsPageViewModel.BookingStateInfo);
}
[Test]
public async Task TestConstruct()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "UnknownCookie", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
viewService);
await settingsPageViewModel.OnAppearing();
Assert.AreEqual("Logged in as a@b at TINK.", settingsPageViewModel.LoggedInInfo);
Assert.IsFalse(settingsPageViewModel.IsBookingStateInfoVisible, "A user is logged but no bikes requested/ booked.");
Assert.AreEqual(string.Empty, settingsPageViewModel.BookingStateInfo);
}
[Test]
public async Task TestConstruct_TwoBikes()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
viewService);
await settingsPageViewModel.OnAppearing();
Assert.AreEqual("Logged in as a@b at TINK.", settingsPageViewModel.LoggedInInfo);
Assert.IsTrue(settingsPageViewModel.IsBookingStateInfoVisible, "A user is logged but no bikes requested/ booked.");
Assert.AreEqual("Aktuell 2 Fahrräder reserviert/ gebucht.", settingsPageViewModel.BookingStateInfo);
}
[Test]
public async Task TestConstruct_TwoBikes_Offline()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false, // Offline
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
viewService);
await settingsPageViewModel.OnAppearing();
Assert.AreEqual("Logged in as a@b at TINK.", settingsPageViewModel.LoggedInInfo);
Assert.IsTrue(settingsPageViewModel.IsBookingStateInfoVisible, "A user is logged but no bikes requested/ booked.");
Assert.AreEqual("Aktuell 2 Fahrräder reserviert/ gebucht. Verbindungsstatus: Offline.", settingsPageViewModel.BookingStateInfo);
}
[Test]
public async Task TestConstruct_TwoBikes_WebConnectCommunicationError()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector(
uri,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie,
mail,
server: new CopriProviderHttps(
uri,
TinkApp.MerchantId,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie: sessionCookie,
cacheServer: new CopriCallsCacheMemory(SampleSets.Set2, sessionCookie: sessionCookie),
httpsServer: new ExceptionServer((msg) => new WebConnectFailureException(msg, new Exception("Source expection."))))),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false, // Offline
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var settingsPageViewModel = new AccountPageViewModel(
tinkApp,
(uri) => { },
viewService);
await settingsPageViewModel.OnAppearing();
Assert.AreEqual("Logged in as a@b at TINK.", settingsPageViewModel.LoggedInInfo);
Assert.IsTrue(settingsPageViewModel.IsBookingStateInfoVisible, "A user is logged but no bikes requested/ booked.");
Assert.AreEqual("Aktuell 2 Fahrräder reserviert/ gebucht. Verbindungsstatus: Offline.", settingsPageViewModel.BookingStateInfo);
}
}
}

View file

@ -0,0 +1,462 @@
using NSubstitute;
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Bikes.Bike.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Model.Services.Geolocation;
using TINK.Model.State;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using TINK.Model.User;
using TINK.Model.Device;
namespace TestTINKLib.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
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
[Test]
public void TestNotSupported()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
var subsequent = handler.HandleRequestOption1().Result;
// Verify that nothing happened because request is not supported.
Assert.AreEqual("BookedDisconnected", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked open
/// </summary>
[Test]
public void TestSearch()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new BookedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Open }.Build()));
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked unknown
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("Tst")));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Unknown);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Internet muss erreichbar sein um Verbindung mit Schloss für gemietetes Rad herzustellen.\r\nContext info\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked unknown
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Unknown);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Kommunikationsfehler bei Schlosssuche.\r\nException message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked unknown
/// </summary>
[Test]
public void TestSearchConnectFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new BookedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => { throw new OutOfReachException(); });
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Fehler bei Verbinden mit Schloss!",
"Schloss kann erst gefunden werden, wenn gemietetes Rad in der Nähe ist.",
"Wiederholen",
"Abbrechen");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked unknown
/// </summary>
[Test]
public void TestSearchConnectFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new BookedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => throw new Exception("Exception message.") );
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAdvancedAlert(
"Fehler bei Verbinden mit Schloss!",
"Lock of rented bike can not be found.",
"Exception message.",
"Wiederholen",
"Abbrechen");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Booked unknown
/// </summary>
[Test]
public void TestSearchConnectNotOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new BookedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(new LockInfoTdo.Builder { State = null }.Build());
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Schlossstatus des gemieteten Rads konnte nicht ermittelt werden.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("BookedDisconnected", handler.ButtonText);
Assert.IsFalse(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
}
}

View file

@ -0,0 +1,590 @@
using NSubstitute;
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Bikes.Bike.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Model.Services.Geolocation;
using TINK.Model.State;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using TINK.Model.User;
using TINK.Model.Device;
namespace TestTINKLib.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
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Reserve bike", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", handler.LockitButtonText);
Assert.IsFalse(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestReserveAndConnectCancel()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
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.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestReserveAndConnect()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(),Arg.Any<TimeSpan>())
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build())); // Return lock state indicating success
locks.TimeOut.Returns(timeOuts);
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
locks[0].OpenAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking call leads to setting of state to booked.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike); // Booking must be performed
bikesViewModel.ActionText = "Opening lock...";
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestReserveAndConnectReserveFailsBookingDeclinedException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
connector.Command.DoReserve(bike).Returns(x => throw new BookingDeclinedException(7)); // Booking must be performed
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Hint", string.Format("A reservation of bike {0} was rejected because the maximum allowed number of {1} reservations/ rentals had already been made.", 0, 7), "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestReserveAndConnectReserveFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
connector.Command.DoReserve(bike).Returns<Task>(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Verbingungsfehler beim Reservieren des Rads!", "Context info.\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestReserveAndConnectReserveFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
connector.Command.DoReserve(bike).Returns<Task>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Closed); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Fehler beim Reservieren des Rads!", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestReserveAndConnectConnectOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>()).Returns<LockInfoTdo>(x => throw new OutOfReachException());
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Schloss außerhalb Reichweite";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestReserveAndConnectConnectException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>()).Returns<LockInfoTdo>(x => throw new Exception("Exception message."));
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Schloss nicht gefunden";
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Reserve bike.
/// Final state: Reserved unknown.
/// </summary>
[Test]
public void TestReserveAndConnectConnectStateUnknown()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new DisposableDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => 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));
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Unknown); // Connect did not throw an exception but lock state is still unknown.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
[Test]
public void TestNotsupported()
{
var handler = new DisposableDisconnected(
Substitute.For<IBikeInfoMutable>(),
() => true, // isConnectedDelegate
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
var subsequent = handler.HandleRequestOption2().Result;
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
}
}

View file

@ -0,0 +1,442 @@
using NSubstitute;
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Bikes.Bike.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Model.Services.Geolocation;
using TINK.Model.State;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using TINK.Model.User;
using TINK.Model.Device;
namespace TestTINKLib.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
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Rent bike or close lock", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual(nameof(DisposableOpen), handler.LockitButtonText);
Assert.IsFalse(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Disposable Closed.
/// </summary>
[Test]
public void TestCloseLock()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseLockCloseFailsOutOfReachExcption()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open);
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Lock can not be closed!", "Lock cannot be closed until bike is near.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual(nameof(DisposableDisconnected), subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseLockCloseFailsExcption()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(false));
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open);
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Lock can not be closed!", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual(nameof(DisposableDisconnected), subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Booked Open.
/// </summary>
[Test]
public void TestDoBook()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Open);
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Disposabled Closed.
/// </summary>
[Test]
public void TestDoBookDoBookFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
connector.Command.DoBook(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
bike.State.Value.Returns(InUseStateEnum.Disposable);
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Connection error when renting the bike!",
string.Format("Attention: Lock is closed!\r\n{0}\r\n{1}", "Context info.", "Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?"),
"OK");
bikesViewModel.ActionText = "Verschließe Schloss...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Lock bike.
/// Final state: Disposabled Closed.
/// </summary>
[Test]
public void TestDoBookDoBookFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 DisposableOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Fahrrad Nr. 0 mieten oder Schloss schließen?", "Mieten", "Schloss schließen").Returns(Task.FromResult(true));
connector.Command.DoBook(bike).Returns(x => throw new Exception("Exception message."));
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
bike.State.Value.Returns(InUseStateEnum.Disposable);
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Error when renting the bike!", "Attention: Lock is closed!\r\nException message.", "OK");
bikesViewModel.ActionText = "Verschließe Schloss...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
}
}

View file

@ -0,0 +1,752 @@
using NSubstitute;
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Bikes.Bike.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Model.Services.Geolocation;
using TINK.Model.State;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using Newtonsoft.Json;
using TINK.Repository.Response;
using TINK.Model.User;
using TINK.Model.Device;
namespace TestTINKLib.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
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: User deceide to abort cancelling (user is ased whether to really cancel)
/// 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 geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(false));
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No");
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Final state: Disposable.
/// </summary>
[Test]
public void TestCancelReservation()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Exception is thrown.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationInvalidAuthorizationResponseException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
var l_oResponse = JsonConvert.DeserializeObject<AuthorizationResponse>(@"
{
""response"" : ""authorization"",
""authcookie"" : ""4da3044c8657a04ba60e2eaa753bc51a"",
""user_group"" : [ ""TINK"", ""Konrad"" ],
""response_state"" : ""OK"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}");
connector.Command.DoCancelReservation(bike).Returns(x => throw new InvalidAuthorizationResponseException("mustermann@server.de", l_oResponse));
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Fehler beim Aufheben der Reservierung!", "Kann Benutzer mustermann@server.de nicht anmelden. Mailadresse unbekannt oder Passwort ungültig.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
connector.Command.DoCancelReservation(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("chub")));
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Verbingungsfehler beim Aufheben der Reservierung!", "Context info\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Cancel reservation.
/// Comment: Canceling reservation fails.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCancelReservationDoCancelReservationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
connector.Command.DoCancelReservation(bike).Returns(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Disconnected); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // 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 = "";
viewService.DisplayAlert("Fehler beim Aufheben der Reservierung!", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: reserved closed
/// </summary>
[Test]
public void TestSearch()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build()));
locks.TimeOut.Returns(timeOuts);
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
locks[0].OpenAsync()
.Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success
bike.State.Value.Returns(InUseStateEnum.Booked); // Booking call leads to setting of state to booked.
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike); // Booking must be performed
bikesViewModel.ActionText = "Opening lock...";
locks.Received()[0].OpenAsync(); // Lock must be opened
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Updating lock state...";
connector.Command.UpdateLockingStateAsync(bike, null);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Unknown);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Internet muss erreichbar sein um Verbindung mit Schloss für reserviertes Rad herzustellen.\r\nContext info.\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchCalculateAuthKeysFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
connector.Command.CalculateAuthKeys(bike).Returns(x => throw new Exception("Exception message."));
bike.State.Value.Returns(InUseStateEnum.Booked);
bike.LockInfo.State.Returns(LockingState.Unknown);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Kommunikationsfehler bei Schlosssuche.\r\nException message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => { throw new OutOfReachException(); });
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Fehler bei Verbinden mit Schloss!",
"Schloss kann erst gefunden werden, wenn reserviertes Rad in der Nähe ist.",
"Wiederholen",
"Abbrechen");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns<Task<LockInfoTdo>>(x => throw new Exception("Execption message."));
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAdvancedAlert(
"Fehler bei Verbinden mit Schloss!",
"Lock of reserved bike can not be found.",
"Execption message.",
"Wiederholen",
"Abbrechen");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Search.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestSearchConnectNotOpen()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 timeOuts = Substitute.For<ITimeOutProvider>();
var handler = new ReservedDisconnected(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
.Returns(new LockInfoTdo.Builder { State = null }.Build());
locks.TimeOut.Returns(timeOuts);
bike.State.Value.Returns(InUseStateEnum.Booked);
var subsequent = handler.HandleRequestOption2().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Request server...";
connector.Command.CalculateAuthKeys(bike);
bikesViewModel.ActionText = "Searching lock...";
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler bei Verbinden mit Schloss!", "Schlossstatus des reservierten Rads konnte nicht ermittelt werden.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Search lock", handler.LockitButtonText);
Assert.IsTrue(handler.IsLockitButtonVisible);
}
}
}

View file

@ -0,0 +1,671 @@
using Newtonsoft.Json;
using NSubstitute;
using NUnit.Framework;
using System;
using System.Threading.Tasks;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Bikes.Bike.BluetoothLock;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Repository.Response;
using TINK.Services.BluetoothLock;
using TINK.Services.BluetoothLock.Exception;
using TINK.Services.BluetoothLock.Tdo;
using TINK.Model.Services.Geolocation;
using TINK.Model.State;
using TINK.View;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
using TINK.Model.User;
using TINK.Model.Device;
namespace TestTINKLib.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
(isConnexted) => Substitute.For<IConnector>(),
Substitute.For<IGeolocation>(),
Substitute.For<ILocksService>(),
() => Substitute.For<IPollingUpdateTaskManager>(),
Substitute.For<ISmartDevice>(),
Substitute.For<IViewService>(),
Substitute.For<IBikesViewModel>(),
Substitute.For<IUser>());
// Verify prerequisites.
Assert.AreEqual("Rad zurückgeben oder mieten", handler.ButtonText);
Assert.IsTrue(handler.IsButtonVisible);
Assert.AreEqual("Alarm/ Sounds verwalten", handler.LockitButtonText);
Assert.IsFalse(handler.IsLockitButtonVisible);
}
/// <summary>
/// Use case: User books bike.
/// Final state: Booked.
/// </summary>
[Test]
public void TestBook()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
bike.State.Value.Returns(InUseStateEnum.Booked); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open); // Requsthandler factory queries lock state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Close lock & return bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: User books bike.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestBookBookFailsWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
connector.Command.DoBook(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Connection error when renting the bike!",
string.Format("Attention: Lock is closed!\r\n{0}\r\n{1}", "Context info.", "Ist WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?"),
"OK");
bikesViewModel.ActionText = "Wiederverschließe Schloss...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: User books bike.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestBookBookFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(false));
connector.Command.DoBook(bike).Returns(x => throw new Exception("Exception message."));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Reading charging level...";
locks[0].GetBatteryPercentageAsync();
bikesViewModel.ActionText = "Renting bike...";
connector.Command.DoBook(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Error when renting the bike!", "Attention: Lock is closed!\r\nException message.", "OK");
bikesViewModel.ActionText = "Wiederverschließe Schloss...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Booked.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservation()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = "Disconnecting lock...";
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Reserved open.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservationCloseFailsOutOfReachException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(
string.Empty,
"Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?",
"Zurückgeben",
"Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => { throw new OutOfReachException(); });
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open);
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Lock can not be closed!",
"Lock cannot be closed until bike is near.\r\nPlease try again to close bike or report bike to support!",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Same as initial state.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservationCloseFailsException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(
string.Empty,
"Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?",
"Zurückgeben",
"Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync()
.Returns<Task<LockitLockingState?>>(x => { throw new Exception("Exception message."); });
bike.State.Value.Returns(InUseStateEnum.Reserved); // Reqesthandler factory queries state to create appropriate request handler object.
bike.LockInfo.State.Returns(LockingState.Open);
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "";
viewService.DisplayAlert(
"Lock can not be closed!",
"Please try to lock again or report bike to support!\r\nException message.",
"OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("Cancel bike reservation", subsequent.ButtonText);
Assert.IsTrue(subsequent.IsButtonVisible);
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
Assert.IsTrue(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservationCancelReservationInvalidAuthorizationResponseException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
var response = JsonConvert.DeserializeObject<AuthorizationResponse>(@"
{
""response"" : ""authorization"",
""authcookie"" : ""4da3044c8657a04ba60e2eaa753bc51a"",
""user_group"" : [ ""TINK"", ""Konrad"" ],
""response_state"" : ""OK"",
""apiserver"" : ""https://tinkwwp.copri-bike.de""
}");
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
connector.Command.DoCancelReservation(bike).Returns(x => throw new InvalidAuthorizationResponseException("mustermann@server.de", response));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
var subsequent = handler.HandleRequestOption1().Result;
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler beim Aufheben der Reservierung!", "Kann Benutzer mustermann@server.de nicht anmelden. Mailadresse unbekannt oder Passwort ungültig.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("InvalidState", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservationCancelReservationWebConnectFailureException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
connector.Command.DoCancelReservation(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("chub")));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Verbingungsfehler beim Aufheben der Reservierung!", "Context info\r\nIst WLAN verfügbar/ Mobilfunknetz vefügbar und mobile Daten aktiviert / ... ?", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("InvalidState", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
/// <summary>
/// Use case: Close lock and cancel reservation.
/// Final state: Reserved closed.
/// </summary>
[Test]
public void TestCloseLockAndCancelReservationCancelReservationException()
{
var bike = Substitute.For<IBikeInfoMutable>();
var connector = Substitute.For<IConnector>();
var command = Substitute.For<ICommand>();
var geolocation = Substitute.For<IGeolocation>();
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 ReservedOpen(
bike,
() => true, // isConnectedDelegate
(isConnexted) => connector,
geolocation,
locks,
() => pollingManager,
Substitute.For<ISmartDevice>(),
viewService,
bikesViewModel,
activeUser);
bike.Id.Returns("0");
viewService.DisplayAlert(string.Empty, "Rad Nr. 0 abschließen und zurückgeben oder Rad mieten?", "Zurückgeben", "Mieten").Returns(Task.FromResult(true));
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
connector.Command.DoCancelReservation(bike).Returns(x => throw new Exception("Exception message.", new Exception("chub")));
bike.State.Value.Returns(InUseStateEnum.Disposable); // Reqesthandler factory queries state to create appropriate request handler object.
var subsequent = handler.HandleRequestOption1().Result;
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
// Verify behaviour
Received.InOrder(() =>
{
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
bikesViewModel.ActionText = "One moment please...";
pollingManager.StopUpdatePeridically(); // Polling must be stopped before any COPR and lock service action
bikesViewModel.ActionText = "Closing lock...";
locks[0].CloseAsync();
bikesViewModel.ActionText = "Canceling reservation...";
connector.Command.DoCancelReservation(bike);
bikesViewModel.ActionText = "";
viewService.DisplayAlert("Fehler beim Aufheben der Reservierung!", "Exception message.", "OK");
bikesViewModel.ActionText = "Updating...";
pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again
bikesViewModel.ActionText = "";
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
});
// Verify state after action
Assert.AreEqual("InvalidState", subsequent.ButtonText);
Assert.IsFalse(subsequent.IsButtonVisible);
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
Assert.IsFalse(subsequent.IsLockitButtonVisible);
}
}
}

View file

@ -0,0 +1,145 @@
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using TestTINKLib.Mocks.Services;
using TINK.Model.Bike.BluetoothLock;
using TINK.Model.Device;
using TINK.Model.State;
using TINK.Model.User;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike.BluetoothLock;
using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler;
namespace TestTINKLib.Fixtures.ObjectTests.Bike.BluetoothLock
{
/// <summary>
/// Moved to TestShareeLib (.Net Core)
/// </summary>
[TestFixture]
public class TestRequestHandlerFactory
{
[Test]
public void TestCreate()
{
// Verify handler for disposable bike.
var bike = new BikeInfoMutable(new BikeInfo("22", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "12"));
Assert.AreEqual(InUseStateEnum.Disposable, bike.State.Value);
Assert.AreEqual(LockingState.Disconnected, bike.LockInfo.State);
Assert.AreEqual(
typeof(DisposableDisconnected),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */ ,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for requested bike with state unknown.
bike = new BikeInfoMutable(new BikeInfo("22", 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>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
Assert.AreEqual(
typeof(ReservedDisconnected),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for requested bike with state closed.
bike = new BikeInfoMutable(new BikeInfo("22", 0 /* lock Id*/, new Guid(), null, null, null, new System.DateTime(2020, 1, 1), "a@b.com", "12", null, null, () => new DateTime(2020, 1, 1), false, new List<string>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
bike.LockInfo.State = LockingState.Closed;
Assert.AreEqual(
typeof(ReservedClosed),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for requested bike with state open.
bike = new BikeInfoMutable(new BikeInfo("22", 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>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
bike.LockInfo.State = LockingState.Open;
Assert.AreEqual(
typeof(ReservedOpen),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for booked bike with state closed.
bike = new BikeInfoMutable(new BikeInfo("22", 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>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
bike.LockInfo.State = LockingState.Closed;
Assert.AreEqual(
typeof(BookedClosed),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for booked bike with state open.
bike = new BikeInfoMutable(new BikeInfo("22", 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>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
bike.LockInfo.State = LockingState.Open;
Assert.AreEqual(
typeof(BookedOpen),
RequestHandlerFactory.Create(
bike,
() => false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
// Verify handler for booked bike with state unknown.
bike = new BikeInfoMutable(new BikeInfo("22", 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>(), TINK.Model.Bike.WheelType.Mono, TINK.Model.Bike.TypeOfBike.Allround));
Assert.AreEqual(
typeof(BookedDisconnected),
RequestHandlerFactory.Create(
bike,
()=> false, // isConnectedDelegate
(connected) => null, // connectorFactory
new GeolocationMock(), // geolocation
new LocksServiceMock(), // LockService
null, // viewUpdateManager
NSubstitute.Substitute.For<ISmartDevice>(),
null /* viewService */,
MockRepository.GenerateStub<IBikesViewModel>(),
MockRepository.GenerateStub<IUser>()).GetType());
}
}
}

View file

@ -0,0 +1,16 @@
using NUnit.Framework;
using TINK.ViewModel.Login;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.CopriWebView
{
[TestFixture]
public class TestManageAccountViewModel
{
[Test]
public void TestUrl()
{
var viewModel = new ManageAccountViewModel("Keks", "Merchant", "Hosti");
Assert.AreEqual("https://Hosti?sessionid=KeksMerchant", viewModel.Uri);
}
}
}

View file

@ -0,0 +1,30 @@
using NUnit.Framework;
using TINK.ViewModel.CopriWebView;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.CopriWebView
{
[TestFixture]
public class TestPasswordForgottonViewModel
{
[Test]
public void TestUrl()
{
var viewModel = new PasswordForgottonViewModel("Merchant", "Hosti");
Assert.AreEqual("https://Hosti/app/Account?sessionid=Merchant", viewModel.Uri);
}
[Test]
public void TestUrl_TINKLive()
{
var viewModel = new PasswordForgottonViewModel("Merchant", "app.tink-konstanz.de");
Assert.AreEqual("https://app.tink-konstanz.de/tinkapp/Account?sessionid=Merchant", viewModel.Uri);
}
[Test]
public void TestUrl_TINK()
{
var viewModel = new PasswordForgottonViewModel("Merchant", "tinkwwp.copri-bike.de");
Assert.AreEqual("https://tinkwwp.copri-bike.de/tinkapp/Account?sessionid=Merchant", viewModel.Uri);
}
}
}

View file

@ -0,0 +1,15 @@
using NUnit.Framework;
using TINK.ViewModel.Info;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Info
{
[TestFixture]
public class TestInfoViewModel
{
[Test]
public void TestOnAppearing()
{
var viewModel = new InfoViewModel("Hosti", false, (url) => string.Empty);
}
}
}

View file

@ -0,0 +1,162 @@
using NUnit.Framework;
using System.Collections.Generic;
using TINK.Model;
using TINK.ViewModel.Map;
namespace UITest.Fixtures.ObjectTests.ViewModel.Map
{
[TestFixture]
public class TestMapPageViewModel
{
/// <summary>
/// Verifies that if Konrad is turned off in settings map page filter does no more contain Konrad option.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_NoKonrad_TinkOnKonradOff()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK" }); // Filters from settings page.
Assert.AreEqual(1, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.On, l_oDict["TINK"]);
}
/// <summary>
/// Verifies that if Konrad is turned off in settings map page filter does no more contain Konrad option.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_NoKonrad_TinkOffKonradOn()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK" }); // Filters from settings page.
Assert.AreEqual(1, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.On, l_oDict["TINK"]);
}
/// <summary>
/// Verifies that if TINK.* is turned off in settings map page filter does no more contain TINK option.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_NoTink_TinkOnKonradOff()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }), // Last map page filter (Konrad was still available but off)
new List<string> { "Konrad" }); // Filters from settings page.
Assert.AreEqual(1, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.On, l_oDict["Konrad"]);
}
/// <summary>
/// Verifies that if Konrad is turned on in settings map page filter is updated with entry Konrad.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_TinkOn()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK", "Konrad" }); // Filters from settings page.
Assert.AreEqual(2, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.Off, l_oDict["TINK"]);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.On, l_oDict["Konrad"]);
}
/// <summary>
/// Verifies that if Konrad is turned on in settings map page filter is updated with entry Konrad.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_TinkOff()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.Off } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK", "Konrad" }); // Filters from settings page.
Assert.AreEqual(2, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.Off, l_oDict["TINK"]);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.On, l_oDict["Konrad"]);
}
/// <summary>
/// Verifies that map page filters are not touched if state is consitend.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_AllOn_KonradActivated()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK", "Konrad" }); // Filters from settings page.
Assert.AreEqual(2, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.Off, l_oDict["TINK"]);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.On, l_oDict["Konrad"]);
}
/// <summary>
/// Verifies that map page filters are not touched if state is consitend..
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_AllOn_TinkActivated()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }), // Last map page filter (Konrad was still available but off)
new List<string> { "TINK", "Konrad" }); // Filters from settings page.
Assert.AreEqual(2, l_oDict.Count);
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.On, l_oDict["TINK"]);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.Off, l_oDict["Konrad"]);
}
/// <summary>
/// Verifies that map page filters are not touched if state is consitend.
/// </summary>
[Test]
public void TestGetFilterDictinaryMapPage_NullFilter()
{
var l_oDict = GroupFilterMapPageHelper.CreateUpdated(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }), // Last map page filter (Konrad was still available but off)
null);
Assert.AreEqual(2, l_oDict.Count, "Do not apply any filter if filter value null is detected.");
Assert.IsTrue(l_oDict.ContainsKey("TINK"));
Assert.AreEqual(FilterState.On, l_oDict["TINK"]);
Assert.IsTrue(l_oDict.ContainsKey("Konrad"));
Assert.AreEqual(FilterState.Off, l_oDict["Konrad"]);
l_oDict = GroupFilterMapPageHelper.CreateUpdated(
null,
null);
Assert.IsNull(l_oDict, "Do not apply any filter if filter value null is detected.");
}
[Test]
public void TestDoToggle()
{
var l_oFilter = new TinkKonradToggleViewModel(new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }));
l_oFilter = new TinkKonradToggleViewModel(l_oFilter.FilterDictionary). DoToggle();
Assert.AreEqual("Konrad", l_oFilter.CurrentFilter);
l_oFilter = new TinkKonradToggleViewModel(l_oFilter.FilterDictionary).DoToggle();
Assert.AreEqual("TINK", l_oFilter.CurrentFilter);
}
}
}

View file

@ -0,0 +1,528 @@
using NUnit.Framework;
using Rhino.Mocks;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestTINKLib.Mocks.Connector;
using TestTINKLib.Mocks.Device;
using TestTINKLib.Mocks.Services;
using TestTINKLib.Model.User.Account;
using TINK.Model;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.Model.Services.CopriApi;
using TINK.Repository;
using TINK.View;
using TINK.ViewModel.Map;
using Xamarin.Forms;
using static TINK.Repository.CopriCallsMemory;
using TINK.ViewModel.Settings;
using TINK.Model.Services.Geolocation;
using TINK.Services;
using NSubstitute;
namespace TestTINKLib.Fixtures.UseCases.Startup
{
[TestFixture]
public class TestMapPageViewModel
{
[Test]
public async Task TestConstruct()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.IsNull(viewModel.Exception);
// Verify pins on map
Assert.AreEqual(8, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"),
"Station 4 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"),
"Station 31 must be marked red because there is no bike.");
// Verify buttons
Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings.");
Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are shown.");
Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are hidden.");
var statusInfoText = viewModel.StatusInfoText;
Assert.That(
statusInfoText,
Does.Contain("Updating...").Or.Contain(""),
$"Unexpected text {statusInfoText} detected.",
"Text might be \"Updating...\" or empty depending on acivity of update thread.");
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_KonradActive()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.IsNull(viewModel.Exception);
// Verify pins on map
Assert.AreEqual(2, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Green"),
"Station 5 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "14").Icon.Id.Contains("Red"),
"Station 14 must be marked red because there is no bike.");
// Verify buttons
Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings.");
Assert.AreEqual(Color.Gray, viewModel.TinkColor, "TINK bikes are hidden.");
Assert.AreEqual(Color.Red, viewModel.KonradColor, "Konrad bikes are shown.");
Assert.IsTrue(
new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText),
"Text might be \"Updating...\" or empty depending on acivity of update thread.");
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_KonradOnly()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "Konrad", FilterState.On } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.IsNull(viewModel.Exception);
// Verify pins on map
Assert.AreEqual(2, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Green"),
"Station 5 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "14").Icon.Id.Contains("Red"),
"Station 14 must be marked red because there is no bike.");
// Verify buttons
Assert.IsFalse(viewModel.IsToggleVisible, "TINK and Konrad is deactivated from settings.");
Assert.IsTrue(
new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText),
"Text might be \"Updating...\" or empty depending on acivity of update thread.");
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_TinkOnly()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173));
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.IsNull(viewModel.Exception);
// Verify pins on map
Assert.AreEqual(8, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"),
"Station 4 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"),
"Station 31 must be marked red because there is no bike.");
// Verify buttons
Assert.IsFalse(viewModel.IsToggleVisible, "TINK and Konrad is deactivated from settings.");
Assert.IsTrue(
new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText),
"Text might be \"Updating...\" or empty depending on acivity of update thread.");
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_Offline()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false,
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.IsNull(viewModel.Exception);
// Verify pins on map
Assert.AreEqual(8, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"),
"Station 4 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"),
"Station 31 must be marked red because there is no bike.");
// Verify buttons
Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings.");
Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are hidden.");
Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown.");
Assert.AreEqual("Offline.", viewModel.StatusInfoText);
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_WebConnectCommunicationError()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
true /* IsReportLevelVerbose */,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector(
uri,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie,
mail,
server: new CopriProviderHttps(
uri,
TinkApp.MerchantId,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie: sessionCookie,
cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie),
httpsServer: new ExceptionServer((msg) => new WebConnectFailureException(msg, new Exception("Source expection."))))),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false,
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.AreEqual(
"Simulated error thrown at GetStationsAsync.",
viewModel.Exception.Message);
// Verify pins on map
Assert.AreEqual(8, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"),
"Station 4 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"),
"Station 31 must be marked red because there is no bike.");
// Verify buttons
Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings.");
Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are hidden.");
Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown.");
Assert.AreEqual("Connection interrupted, server unreachable.", viewModel.StatusInfoText);
}
finally
{
await viewModel.OnDisappearing();
}
}
[Test]
public async Task TestConstruct_GeneralPurposeCommunicationError()
{
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
true /* IsReportLevelVerbose */,
activeLockService: typeof(LocksServiceMock).FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector(
uri,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie,
mail,
server: new CopriProviderHttps(
uri,
TinkApp.MerchantId,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie: sessionCookie,
cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie),
httpsServer: new ExceptionServer((msg) => new Exception(msg)))),
Substitute.For<IServicesContainer<IGeolocation>>(),
new LocksServiceMock(),
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false,
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to
var viewService = MockRepository.GenerateStub<IViewService>();
var navigationService = MockRepository.GenerateStub<INavigation>();
var viewModel = new MapPageViewModel(
tinkApp,
new PermissionsMock(),
NSubstitute.Substitute.For<Plugin.BLE.Abstractions.Contracts.IBluetoothLE>(),
NSubstitute.Substitute.For<IGeolocation>(),
(mapspan) => { },
viewService,
navigationService);
try
{
await viewModel.OnAppearing(); // Is called when page shows.
Assert.AreEqual(
"Simulated error thrown at GetStationsAsync.",
viewModel.Exception.Message);
// Verify pins on map
Assert.AreEqual(8, viewModel.Pins.Count);
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"),
"Station 4 must be marked green because there is are bike.");
Assert.IsTrue(
viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"),
"Station 31 must be marked red because there is no bike.");
// Verify buttons
Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings.");
Assert.AreEqual(Color.Blue , viewModel.TinkColor, "TINK bikes are hidden.");
Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown.");
Assert.AreEqual("Connection interrupted.", viewModel.StatusInfoText);
}
finally
{
await viewModel.OnDisappearing();
}
}
}
}

View file

@ -0,0 +1,110 @@
using NUnit.Framework;
using System.Collections.Generic;
using TINK.Model;
using TINK.ViewModel.Settings;
namespace UITest.Fixtures.ObjectTests.ViewModel.Settings
{
[TestFixture]
public class TestFilterCollectionMutable
{
[Test]
public void TestConstruct_NoConradAccount()
{
var l_oColl = new SettingsBikeFilterViewModel(
new GroupFilterSettings(new Dictionary<string, FilterState> {
{"TINK", FilterState.On },
{"Konrad", FilterState.On}
}),
new List<string> { "TINK" });
Assert.AreEqual("TINK", l_oColl[0].Key);
Assert.IsTrue(l_oColl[0].IsActivated);
Assert.IsTrue(l_oColl[0].IsEnabled);
Assert.AreEqual("Konrad", l_oColl[1].Key);
Assert.IsFalse(l_oColl[1].IsActivated, "Konrad must be off if user is not part of group.");
Assert.IsFalse(l_oColl[1].IsEnabled, "Konrad must be disabled if user is not part of group.");
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["TINK"]);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["Konrad"], "Filter state must be preserved.");
}
[Test]
public void TestConstruct_ConradAccount()
{
var l_oColl = new SettingsBikeFilterViewModel(
new GroupFilterSettings(new Dictionary<string, FilterState> {
{"TINK", FilterState.On },
{"Konrad", FilterState.On}
}),
new List<string> { "TINK", "Konrad" });
Assert.AreEqual("TINK", l_oColl[0].Key);
Assert.IsTrue(l_oColl[0].IsActivated);
Assert.IsTrue(l_oColl[0].IsEnabled);
Assert.AreEqual("Konrad", l_oColl[1].Key);
Assert.IsTrue(l_oColl[1].IsActivated);
Assert.IsTrue(l_oColl[1].IsEnabled);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["TINK"]);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["Konrad"], "Filter state must be preserved.");
}
[Test]
public void TestConstruct_TurnOff()
{
var l_oColl = new SettingsBikeFilterViewModel(
new GroupFilterSettings(new Dictionary<string, FilterState> {
{"TINK", FilterState.On },
{"Konrad", FilterState.On}
}),
new List<string> { "TINK", "Konrad" });
// Check prerequisites.
Assert.AreEqual("TINK", l_oColl[0].Key);
Assert.IsTrue(l_oColl[0].IsActivated);
Assert.IsTrue(l_oColl[0].IsEnabled);
Assert.AreEqual("Konrad", l_oColl[1].Key);
Assert.IsTrue(l_oColl[1].IsActivated);
Assert.IsTrue(l_oColl[1].IsEnabled);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["TINK"]);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["Konrad"], "Filter state must be preserved.");
// Turn filter konrad off.
l_oColl[1].IsActivated = false;
// Verify changes.
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["TINK"]);
Assert.AreEqual(FilterState.Off, l_oColl.FilterCollection["Konrad"], "Filter state must be preserved.");
}
[Test]
public void TestConstruct_NoUserLoggedIn()
{
var l_oColl = new SettingsBikeFilterViewModel(
new GroupFilterSettings(new Dictionary<string, FilterState> {
{"TINK", FilterState.On },
{"Konrad", FilterState.On}
}),
null);
// Check prerequisites.
Assert.AreEqual("TINK", l_oColl[0].Key);
Assert.IsTrue(l_oColl[0].IsActivated);
Assert.IsTrue(l_oColl[0].IsEnabled);
Assert.AreEqual("Konrad", l_oColl[1].Key);
Assert.IsTrue(l_oColl[1].IsActivated);
Assert.IsTrue(l_oColl[1].IsEnabled);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["TINK"]);
Assert.AreEqual(FilterState.On, l_oColl.FilterCollection["Konrad"], "Filter state must be preserved.");
}
}
}

View file

@ -0,0 +1,27 @@
using NUnit.Framework;
using System;
using TINK.ViewModel;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
{
[TestFixture]
public class TestBikeAtStationInUseStateInfoProvider
{
[Test]
public void TestGetReservedInfo()
{
Assert.That(new BikeAtStationInUseStateInfoProvider().GetReservedInfo(null), Is.EqualTo("Max. reservation time of 15 minutes expired."));
Assert.That(new BikeAtStationInUseStateInfoProvider().GetReservedInfo(null, code: "Code123"), Is.Not.Null);
Assert.That(new BikeAtStationInUseStateInfoProvider().GetReservedInfo(TimeSpan.FromSeconds(3), code: "Code123"), Is.Not.Null);
Assert.That(new BikeAtStationInUseStateInfoProvider().GetReservedInfo(TimeSpan.FromSeconds(60)), Is.EqualTo("Still 1 minutes reserved."));
}
[Test]
public void Test()
{
Assert.That(new BikeAtStationInUseStateInfoProvider().GetBookedInfo(null), Is.EqualTo("Bike is rented."));
Assert.That(new BikeAtStationInUseStateInfoProvider().GetBookedInfo(DateTime.Parse("2020-12-19 0:22"), code: "Code123"), Is.Not.Null);
Assert.That(new BikeAtStationInUseStateInfoProvider().GetBookedInfo(DateTime.Parse("2020-12-19 0:22"), code: "Code123"), Is.EqualTo("Code Code123, rented since 19. December 00:22."));
}
}
}

View file

@ -0,0 +1,223 @@
using NUnit.Framework;
using System;
using TINK.Model.Bike;
using TINK.Model.User;
using TINK.Model.User.Account;
using TINK.ViewModel;
using TestTINKLib.Model.User.Account;
using Xamarin.Forms;
using TINK.Model.State;
using Rhino.Mocks;
using System.Collections.Generic;
using BikeInfoMutable = TINK.Model.Bike.BC.BikeInfoMutable;
using TINK.ViewModel.Bikes;
using TINK.Model.Device;
namespace UITest.Fixtures.ViewModel
{
[TestFixture]
public class TestBikeAtStationViewModel
{
private class BikeInfoMutable : TINK.Model.Bike.BC.BikeInfoMutable
{
public BikeInfoMutable(
string p_iId,
bool p_bIsDemo = false,
IEnumerable<string> p_oGroup = null,
WheelType? p_eWheelType = null,
TypeOfBike? p_eTypeOfBike = null,
string description = null,
string p_strCurrentStationName = null,
Uri operatorUri = null,
Func<DateTime> p_oDateTimeProvider = null,
IStateInfo stateInfo = null) : base(p_iId, p_bIsDemo, p_oGroup, p_eWheelType, p_eTypeOfBike, description, p_strCurrentStationName, operatorUri, null, p_oDateTimeProvider, stateInfo)
{
}
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_NotLoggedIn()
{
var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, 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.AreEqual(InUseStateEnum.Disposable, l_oBike.State.Value);
Assert.IsFalse(l_oUser.IsLoggedIn);
// Verify view model.
var l_oViewModel = new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
l_oBike,
l_oUser,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>());
Assert.AreEqual("2", l_oViewModel.Name);
Assert.AreEqual("", l_oViewModel.DisplayId);
Assert.AreEqual("2", l_oViewModel.Id);
Assert.AreEqual("Available.", l_oViewModel.StateText);
Assert.AreEqual(Color.Default, l_oViewModel.StateColor);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_Reserved()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Reserved(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual("Still 15 minutes reserved.", l_oViewModel.StateText);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_ReservedWithCopriConnect()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_ReservedWithCopriConnect(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual("Code 4asdfA, still 7 minutes reserved.", l_oViewModel.StateText);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_Booked()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Booked(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new BikeAtStationInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual(
$"Code 4asdfA, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.",
l_oViewModel.StateText);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_ReservedBySomeoneElse()
{
var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo, "Test description", "3");
l_oBike.State.Load(
InUseStateEnum.Reserved,
new DateTime(2017, 10, 24, 21, 49, 3),
"ragu@gnu-systems.de",
"4asdfA");
var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));
var l_oViewModel = new TINK.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(),
MockRepository.GenerateStub<IBikesViewModel>());
Assert.AreEqual("Test description", l_oViewModel.Name);
Assert.AreEqual("2", l_oViewModel.DisplayId);
Assert.AreEqual("2", l_oViewModel.Id);
Assert.AreEqual("Fahrrad bereits reserviert durch anderen Nutzer.", l_oViewModel.StateText);
Assert.AreEqual(Color.Red, l_oViewModel.StateColor);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_BookedBySomeoneElse()
{
var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo, "Test description", "3");
l_oBike.State.Load(
InUseStateEnum.Booked,
new DateTime(2017, 10, 24, 21, 49, 3),
"ragu@gnu-systems.de",
"4asdfA");
var l_oStoreMock = new StoreMock(new Account("john@long", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));
var l_oViewModel = new TINK.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(),
MockRepository.GenerateStub<IBikesViewModel>());
Assert.AreEqual("Test description", l_oViewModel.Name);
Assert.AreEqual("2", l_oViewModel.DisplayId);
Assert.AreEqual("2", l_oViewModel.Id);
Assert.AreEqual("Fahrrad bereits gebucht durch anderen Nutzer.", l_oViewModel.StateText);
Assert.AreEqual(Color.Red, l_oViewModel.StateColor);
}
}
}

View file

@ -0,0 +1,144 @@
using NUnit.Framework;
using System;
using TINK.Model.Bike;
using TINK.Model.User;
using TINK.Model.User.Account;
using TINK.ViewModel;
using TestTINKLib.Model.User.Account;
using static TINK.Repository.CopriCallsMemory;
using TINK.Model.State;
using System.Collections.Generic;
using TINK.Repository;
using TINK.ViewModel.Bikes.Bike;
namespace UITest.Fixtures.ViewModel
{
public class TestBikeViewModel
{
private class BikeInfoMutable : TINK.Model.Bike.BC.BikeInfoMutable
{
public BikeInfoMutable(
string p_iId,
bool p_bIsDemo = false,
IEnumerable<string> p_oGroup = null,
WheelType? p_eWheelType = null,
TypeOfBike? p_eTypeOfBike = null,
string description = null,
string p_strCurrentStationName = null,
Uri operatorUri = null,
Func<DateTime> p_oDateTimeProvider = null,
IStateInfo stateInfo = null) : base(p_iId, p_bIsDemo, p_oGroup, p_eWheelType, p_eTypeOfBike, description, p_strCurrentStationName, operatorUri, null, p_oDateTimeProvider, stateInfo)
{
}
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_Reserved(Func<TINK.Model.Bike.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable(
"2",
false,
new List<string> { "TINK" },
WheelType.Trike,
TypeOfBike.Cargo,
"Test description",
"3",
null,
() => new DateTime(1980, 1, 1)); // Now time stamp
// Update state from Copri.
l_oBike.State.Load(
InUseStateEnum.Reserved, // Copri acknowledges state reserved.
new DateTime(1980, 1, 1), // Date when bike was booked.
"ragu@gnu-systems.de"); // Owner from Copri.
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));
var l_oUser = new User(
l_oStoreMock,
l_oStoreMock.Load().Result,
"123456789");
// Verify prerequisites
Assert.AreEqual(InUseStateEnum.Reserved, l_oBike.State.Value);
Assert.IsTrue(l_oUser.IsLoggedIn);
Assert.AreEqual(l_oBike.State.MailAddress, l_oUser.Mail);
// Do not update from Copri
var l_oViewModel = p_oFactory(l_oBike, l_oUser);
return l_oViewModel;
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_ReservedWithCopriConnect(Func<TINK.Model.Bike.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable(
"2",
false,
new List<string> { "TINK" },
WheelType.Trike,
TypeOfBike.Cargo,
"Test description",
"3",
null,
() => (new DateTime(1980, 1, 1)).Add(new TimeSpan(0, 8, 0)));
// Update state from Copri.
l_oBike.State.Load(
InUseStateEnum.Reserved, // Copri acknowledges state reserved.
new DateTime(1980, 1, 1),
"ragu@gnu-systems.de", // Owner from Copri.
"4asdfA"); // Reservation code from Copri
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));
var l_oUser = new User(
l_oStoreMock, // Mocks account store functionality.
l_oStoreMock.Load().Result,
"123456789");
// Verify prerequisites
Assert.AreEqual(InUseStateEnum.Reserved, l_oBike.State.Value);
Assert.IsTrue(l_oUser.IsLoggedIn);
Assert.AreEqual(l_oBike.State.MailAddress, l_oUser.Mail);
var l_oViewModel = p_oFactory(l_oBike, l_oUser); // Bikes collection mock.
return l_oViewModel;
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
public static BikeViewModelBase TestStateText_LoggedIn_Booked(Func<TINK.Model.Bike.BC.BikeInfoMutable, User, BikeViewModelBase> p_oFactory)
{
var l_oBike = new BikeInfoMutable("2", false, new List<string> { "TINK" }, WheelType.Two, TypeOfBike.Cargo, "Test description", "3");
// Update from Copri.
l_oBike.State.Load(
InUseStateEnum.Booked,
new DateTime(2017, 10, 24, 21, 49, 3),
"ragu@gnu-systems.de",
"4asdfA");
var l_oCopriServer = new CopriCallsMemory(SampleSets.Set1, 1);
var l_oStoreMock = new StoreMock(new Account("ragu@gnu-systems.de", "123456789" /* password */, "987654321" /* session cookie */, new List<string> { "TINK" }));
var l_oUser = new User(
l_oStoreMock,
l_oStoreMock.Load().Result,
"123456789"); // Device id
// Verify prerequisites
Assert.AreEqual(InUseStateEnum.Booked, l_oBike.State.Value);
Assert.IsTrue(l_oUser.IsLoggedIn);
Assert.AreEqual(l_oBike.State.MailAddress, l_oUser.Mail);
var l_oViewModel = p_oFactory(l_oBike, l_oUser);
return l_oViewModel;
}
}
}

View file

@ -0,0 +1,52 @@
using NUnit.Framework;
using Rhino.Mocks;
using System;
using TestTINKLib.Mocks.Services;
using TINK.Model.Device;
using TINK.Model.User;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
using TINK.ViewModel.Bikes.Bike;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
{
[TestFixture]
public class TestBikeViewModelFactory
{
[Test]
public void TestCreate()
{
Assert.AreEqual(
typeof(TINK.ViewModel.Bikes.Bike.BC.BikeViewModel),
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 TINK.Model.Bike.BC.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42")),
MockRepository.GenerateStub<IUser>(), // user
MockRepository.GenerateStub<IInUseStateInfoProvider>(),
MockRepository.GenerateStub<IBikesViewModel>()).GetType()); // stateInfoProvider
Assert.AreEqual(
typeof(TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel),
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 TINK.Model.Bike.BluetoothLock.BikeInfoMutable(new TINK.Model.Bike.BluetoothLock.BikeInfo("42", 5200544, new Guid("00000000-0000-0000-0000-000000000001"), "42")),
MockRepository.GenerateStub<IUser>(), // user
MockRepository.GenerateStub<IInUseStateInfoProvider>(),
MockRepository.GenerateStub<IBikesViewModel>()).GetType()); // stateInfoProvider
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,31 @@
using NUnit.Framework;
using System;
using TINK.ViewModel;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
{
[TestFixture]
public class TestMyBikeInUseStateInfoProvider
{
[Test]
public void TestGetReservedInfo()
{
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(null), Is.EqualTo("Max. reservation time of 15 minutes expired."));
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(null, code: "Code12"), Is.Not.Null);
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(null, "12"), Is.EqualTo("Location 12, max. reservation time of 15 minutes expired."));
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(null, "12", "Code12"), Is.Not.Null);
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(TimeSpan.FromSeconds(10)), Is.Not.Null);
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(TimeSpan.FromSeconds(10), "123"), Is.EqualTo("Location Station 123, still 0 minutes reserved."));
Assert.That(new MyBikeInUseStateInfoProvider().GetReservedInfo(TimeSpan.FromSeconds(10), "123", "code123"), Is.Not.Null);
}
[Test]
public void TestGetBookedInfoInfo()
{
Assert.That(new MyBikeInUseStateInfoProvider().GetBookedInfo(null), Is.EqualTo("Bike is rented."));
Assert.That(new MyBikeInUseStateInfoProvider().GetBookedInfo(DateTime.Now, "123", "Code123"), Is.Not.Null);
Assert.That(new MyBikeInUseStateInfoProvider().GetBookedInfo(DateTime.Now, code: "Code123"), Is.Not.Null);
Assert.That(new MyBikeInUseStateInfoProvider().GetBookedInfo(DateTime.Parse("2020-12-19 0:22"), "123"), Is.EqualTo("Rented since 19. December 00:22."));
}
}
}

View file

@ -0,0 +1,85 @@
using NUnit.Framework;
using Rhino.Mocks;
using System;
using TINK.Model.Device;
using TINK.ViewModel;
using TINK.ViewModel.Bikes;
namespace UITest.Fixtures.ViewModel
{
[TestFixture]
public class TestMyBikesPageViewModel
{
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_Reserved()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Reserved(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual("Location Station 3, still 15 minutes reserved.", l_oViewModel.StateText);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
[Test]
public void TestStateText_LoggedIn_ReservedWithCopriConnect()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_ReservedWithCopriConnect(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual("Code 4asdfA, location Station 3, still 7 minutes reserved.", l_oViewModel.StateText);
}
/// <summary>
/// Tests base class functionaltiy by using child.
/// </summary>
///
[Test]
public void TestStateText_LoggedIn_Booked()
{
var l_oViewModel = TestBikeViewModel.TestStateText_LoggedIn_Booked(
(bike, user) => new TINK.ViewModel.Bikes.Bike.BC.BikeViewModel(
null,
null,
null,
null,
NSubstitute.Substitute.For<ISmartDevice>(),
null,
bike,
user,
new MyBikeInUseStateInfoProvider(),
MockRepository.GenerateStub<IBikesViewModel>()));
Assert.AreEqual(
$"Code 4asdfA, location Station 3, rented since {new DateTime(2018, 10, 24, 21, 49, 00).ToString("dd. MMMM HH:mm")}.",
l_oViewModel.StateText);
}
}
}

View file

@ -0,0 +1,788 @@
using NUnit.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TestTINKLib.Mocks.Connector;
using TestTINKLib.Mocks.Device;
using TestTINKLib.Mocks.Services;
using TestTINKLib.Model.User.Account;
using TINK.Model;
using TINK.Model.Connector;
using TINK.Repository.Exception;
using TINK.View;
using TINK.Model.Services.CopriApi;
using TINK.Repository;
using static TINK.Repository.CopriCallsMemory;
using TINK.ViewModel.Map;
using TINK.ViewModel.Settings;
using Plugin.Permissions.Abstractions;
using Plugin.BLE.Abstractions.Contracts;
using TINK.Services.BluetoothLock;
using NSubstitute;
using TINK.Services.BluetoothLock.Tdo;
using TINK.ViewModel.MyBikes;
using Plugin.Permissions;
using Xamarin.Forms;
using TINK.Model.Services.Geolocation;
using NSubstitute.ExceptionExtensions;
using TINK.Services;
using TINK.Model.Device;
namespace TestTINKLib.Fixtures.ObjectTests.ViewModel
{
[TestFixture]
public class TestMyBikesPageViewModel
{
[Test]
public async Task TestConstruct_Droid()
{
var geolocation = Substitute.For<IServicesContainer<IGeolocation>>();
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
// Fake location permissions to be set
permissions.CheckPermissionStatusAsync<LocationPermission>().Returns(Task.FromResult(PermissionStatus.Granted));
geolocation.Active.IsGeolcationEnabled.Returns(true); // Fake gps to be on
bluetooth.State.Returns(BluetoothState.On); // Fake bluetooth to be on
// Fake bluetooth answer for locks with id 2200545 and 2200537.
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>()).Returns(
new List<LockInfoTdo> {
{ new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() },
{ new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() }
}
);
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List<string> { "300001", "300029" } )),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, sessionCookie)),
geolocation,
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions, /* permissions */
bluetooth, /* bluetooth */
Device.Android,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
geolocation.Active, // geolocation
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
// Verify behaviour
Received.InOrder(() =>
{
permissions.CheckPermissionStatusAsync<LocationPermission>();
var glDummy = geolocation.Active.Received().IsGeolcationEnabled;
var btDummy = bluetooth.Received().State;
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>());
});
Assert.IsEmpty(myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
var bike1545 = myBikes.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
var bike1537 = myBikes.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
Assert.AreEqual("Rented since 06. November 17:53.", bike1545.StateText);
Assert.AreEqual("Rented since 12. October 08:38.", bike1537.StateText);
Assert.AreEqual("Close lock", bike1545.LockitButtonText);
Assert.AreEqual("Open lock & continue renting", bike1537.LockitButtonText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.IsEmpty(myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_Droid_NoPermissions_OpenSettings()
{
var geolocation = Substitute.For<IServicesContainer<IGeolocation>>();
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
// Fake location permissions not to be set
permissions.CheckPermissionStatusAsync<LocationPermission>().Returns(Task.FromResult(PermissionStatus.Denied));
// Fake anwser on question whether to open permissions dialog
viewService.DisplayAlert(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>()).Returns(true);
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>()).Returns(
new List<LockInfoTdo> {
{ new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() },
{ new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() }
}
);
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List<string> { "300001", "300029" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, sessionCookie)),
geolocation,
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions, /* permissions */
bluetooth, /* bluetooth */
Device.Android,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
geolocation.Active, // geolocation
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
// Verify behaviour
Received.InOrder(() =>
{
permissions.CheckPermissionStatusAsync<LocationPermission>();
var glDummy = geolocation.Active.Received().IsGeolcationEnabled;
permissions.RequestPermissionAsync<LocationPermission>(); // Ask user from permissions.
viewService.DisplayAlert(
"Hint",
"Please allow location sharing so that bike lock/locks can be managed.\r\nOpen sharing dialog?",
"Yes",
"No");
permissions.OpenAppSettings();
});
Assert.IsEmpty(myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
var bike1545 = myBikes.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
var bike1537 = myBikes.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
Assert.AreEqual("Rented since 06. November 17:53.", bike1545.StateText);
Assert.AreEqual("Rented since 12. October 08:38.", bike1537.StateText);
Assert.AreEqual("Search lock", bike1545.LockitButtonText);
Assert.AreEqual("Search lock", bike1537.LockitButtonText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.IsEmpty(myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_Droid_NoPermissions()
{
var geolocation = Substitute.For<IServicesContainer<IGeolocation>>();
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
// Fake location permissions not to be set
permissions.CheckPermissionStatusAsync<LocationPermission>().Returns(Task.FromResult(PermissionStatus.Denied));
permissions.OpenAppSettings().Throws<Exception>(); // Ensures that method is not called and fixture succeeds.
// Fake anwser on question whether to open permissions dialog
viewService.DisplayAlert(Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>(), Arg.Any<string>()).Returns(false);
// Fake bluetooth answer for locks with id 2200545 and 2200537.
var lockInfoTdo = new List<LockInfoTdo> {
{ new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() },
{ new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() }
};
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>()).Returns(lockInfoTdo);
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List<string> { "300001", "300029" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, sessionCookie)),
geolocation,
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions, /* permissions */
bluetooth, /* bluetooth */
Device.Android,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
geolocation.Active, // geolocation
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
// Verify behaviour
Received.InOrder(() =>
{
permissions.CheckPermissionStatusAsync<LocationPermission>();
var glDummy = geolocation.Active.Received().IsGeolcationEnabled;
permissions.RequestPermissionAsync<LocationPermission>(); // Ask user from permissions.
viewService.DisplayAlert(
"Hint",
"Please allow location sharing so that bike lock/locks can be managed.\r\nOpen sharing dialog?",
"Yes",
"No");
});
Assert.IsEmpty(myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
var bike1545 = myBikes.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
var bike1537 = myBikes.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
Assert.AreEqual("Rented since 06. November 17:53.", bike1545.StateText);
Assert.AreEqual("Rented since 12. October 08:38.", bike1537.StateText);
Assert.AreEqual("Search lock", bike1545.LockitButtonText);
Assert.AreEqual("Search lock", bike1537.LockitButtonText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.IsEmpty(myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_Droid_GeolocationOff()
{
var geolocation = Substitute.For<IServicesContainer<IGeolocation>>();
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
// Fake location permissions to be set
permissions.CheckPermissionStatusAsync<LocationPermission>().Returns(Task.FromResult(PermissionStatus.Granted));
geolocation.Active.IsGeolcationEnabled.Returns(false); // Fake gps to be off
// Fake bluetooth answer for locks with id 2200545 and 2200537.
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>()).Returns(
new List<LockInfoTdo> {
{ new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() },
{ new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() }
}
);
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List<string> { "300001", "300029" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, sessionCookie)),
geolocation,
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions, /* permissions */
bluetooth, /* bluetooth */
Device.Android,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
geolocation.Active, // geolocation
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
// Verify behaviour
Received.InOrder(() =>
{
permissions.CheckPermissionStatusAsync<LocationPermission>();
var glDummy = geolocation.Active.Received().IsGeolcationEnabled;
viewService.DisplayAlert(
"Hint",
"Please activate location so that bike lock can be found!",
"OK");
});
Assert.IsEmpty(myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
var bike1545 = myBikes.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
var bike1537 = myBikes.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
Assert.AreEqual("Rented since 06. November 17:53.", bike1545.StateText);
Assert.AreEqual("Rented since 12. October 08:38.", bike1537.StateText);
Assert.AreEqual("Search lock", bike1545.LockitButtonText);
Assert.AreEqual("Search lock", bike1537.LockitButtonText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.IsEmpty(myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_Droid_BluetoothOff()
{
var geolocation = Substitute.For<IServicesContainer<IGeolocation>>();
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
// Fake location permissions to be set
permissions.CheckPermissionStatusAsync<LocationPermission>().Returns(Task.FromResult(PermissionStatus.Granted));
geolocation.Active.IsGeolcationEnabled.Returns(true); // Fake gps to be on
bluetooth.State.Returns(BluetoothState.Off); // Fake bluetooth to be off
var lockInfoTdo = new List<LockInfoTdo> {
{ new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() },
{ new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() }
};
locksService.GetLocksStateAsync(Arg.Any<IEnumerable<LockInfoAuthTdo>>(), Arg.Any<TimeSpan>()).Returns(lockInfoTdo);
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List<string> { "300001", "300029" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, sessionCookie)),
geolocation,
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions, /* permissions */
bluetooth, /* bluetooth */
Device.Android,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
geolocation.Active, // geolocation
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
// Verify behaviour
Received.InOrder(() =>
{
permissions.CheckPermissionStatusAsync<LocationPermission>();
var glDummy = geolocation.Active.Received().IsGeolcationEnabled;
var btDummy = bluetooth.Received().State;
viewService.DisplayAlert(
"Hint",
"Please enable Bluetooth to manage bike lock/locks.",
"OK");
});
Assert.IsEmpty(myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
var bike1545 = myBikes.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
var bike1537 = myBikes.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel;
Assert.AreEqual("Rented since 06. November 17:53.", bike1545.StateText);
Assert.AreEqual("Rented since 12. October 08:38.", bike1537.StateText);
Assert.AreEqual("Search lock", bike1545.LockitButtonText);
Assert.AreEqual("Search lock", bike1537.LockitButtonText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.IsEmpty(myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_NoBikesOccupied()
{
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "Invalid_SessionCookie", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => true,
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions,
bluetooth,
Device.iOS,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
new GeolocationMock(),
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
Assert.IsTrue(new List<string> { "Updating...", string.Empty }.Contains(myBikes.StatusInfoText));
Assert.AreEqual(0, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsFalse(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
Assert.IsTrue(myBikes.IsNoBikesOccupiedVisible);
Assert.AreEqual("Momentan sind keine Fahrräder auf Benutzer a@b reserviert/ gebucht.", myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestConstruct_Offline()
{
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => false, // Offline
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions,
bluetooth,
Device.iOS,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
new GeolocationMock(),
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService);
await myBikes.OnAppearing();
Assert.AreEqual("Offline.", myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
Assert.AreEqual("Code 2931, location Station 4, rented since 28. November 13:06.", myBikes.FirstOrDefault(x => x.Id == "7").StateText);
Assert.AreEqual("Code 3630, location Station 5, rented since 28. November 11:01.", myBikes.FirstOrDefault(x => x.Id == "8").StateText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.AreEqual(string.Empty, myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestTinkApp_WebConnectCommunicationError()
{
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector(
uri,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default automated test envirnoment",
sessionCookie,
mail,
server: new CopriProviderHttps(
uri,
TinkApp.MerchantId,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default automated test envirnoment",
sessionCookie: sessionCookie,
cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie),
httpsServer: new ExceptionServer((msg) => new WebConnectFailureException(msg, new Exception("Source expection."))))),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
new PermissionsMock(),
isConnectedFunc: () => false, // Offline
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions,
bluetooth,
Device.iOS,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
new GeolocationMock(),
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService)
{
IsReportLevelVerbose = true
};
await myBikes.OnAppearing();
Assert.AreEqual("Connection interrupted, server unreachable.", myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
Assert.AreEqual("Code 2931, location Station 4, rented since 28. November 13:06.", myBikes.FirstOrDefault(x => x.Id == "7").StateText);
Assert.AreEqual("Code 3630, location Station 5, rented since 28. November 11:01.", myBikes.FirstOrDefault(x => x.Id == "8").StateText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.AreEqual(string.Empty, myBikes.NoBikesOccupiedText);
}
[Test]
public async Task TestTinkApp_GeneralPurposeError()
{
var locksService = Substitute.For<ILocksService>();
var timeOut = Substitute.For<ITimeOutProvider>();
var viewService = Substitute.For<IViewService>();
var permissions = Substitute.For<IPermissions>();
var bluetooth = Substitute.For<IBluetoothLE>();
locksService.TimeOut.Returns(timeOut);
timeOut.MultiConnect.Returns(new TimeSpan(0));
var tinkApp = new TinkApp(
new TINK.Model.Settings.Settings(
new GroupFilterMapPage(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }),
new GroupFilterSettings(new Dictionary<string, FilterState> { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }),
new Uri("https://shareeapp-primary.copri-bike.de/APIjsonserver"),
new TINK.Settings.PollingParameters(new TimeSpan(10000), true),
Serilog.Events.LogEventLevel.Error,
activeLockService: locksService.GetType().FullName,
activeGeolocationService: typeof(GeolocationMock).FullName),
new StoreMock(new TINK.Model.User.Account.Account("a@b", "123456789", "4da3044c8657a04ba60e2eaa753bc51a", new List<string> { "TINK" })),
(isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector(
uri,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie,
mail,
server: new CopriProviderHttps(
uri,
TinkApp.MerchantId,
"TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default",
sessionCookie: sessionCookie,
cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie),
httpsServer: new ExceptionServer((msg) => new Exception(msg)))),
Substitute.For<IServicesContainer<IGeolocation>>(),
locksService,
new DeviceMock(),
new SpecialFolderMock(),
null, // Cipher
permissions,
isConnectedFunc: () => false, // Offline
postAction: (d, obj) => d(obj),
currentVersion: new Version(3, 2, 0, 115), // Current app version
lastVersion: new Version(3, 0, 173), // Current app version. Must be larger or equal 3.0.173 to
whatsNewShownInVersion: null); // Whats new page was never shown.
var myBikes = new MyBikesPageViewModel(
tinkApp.ActiveUser,
permissions,
bluetooth,
Device.iOS,
() => tinkApp.GetIsConnected(),
(isConnected) => tinkApp.GetConnector(isConnected),
new GeolocationMock(),
locksService,
tinkApp.Polling,
(d, obj) => d(obj),
Substitute.For<ISmartDevice>(),
viewService)
{
IsReportLevelVerbose = true
};
await myBikes.OnAppearing();
Assert.AreEqual("Connection interrupted.", myBikes.StatusInfoText);
Assert.AreEqual(2, myBikes.Count);
Assert.IsTrue(myBikes.IsIdle);
Assert.IsTrue(myBikes.IsBikesListVisible, "If there are any bikes, list must be visible.");
Assert.AreEqual("Code 2931, location Station 4, rented since 28. November 13:06.", myBikes.FirstOrDefault(x => x.Id == "7").StateText);
Assert.AreEqual("Code 3630, location Station 5, rented since 28. November 11:01.", myBikes.FirstOrDefault(x => x.Id == "8").StateText);
Assert.IsFalse(myBikes.IsNoBikesOccupiedVisible);
Assert.AreEqual(string.Empty, myBikes.NoBikesOccupiedText);
}
}
}

View file

@ -0,0 +1,83 @@
using NUnit.Framework;
using Rhino.Mocks;
using TINK.Model.Bike;
using TINK.Model.Bikes.Bike.BC;
using TINK.ViewModel;
namespace UITest.Fixtures.ObjectTests.ViewModel
{
[TestFixture]
public class TestViewModelHelper
{
[Test]
public void TestGetDisplayName_DefinedTypes()
{
var l_oBike = MockRepository.GenerateStub<IBikeInfoMutable>();
l_oBike.Stub(x => x.WheelType).Return(WheelType.Two);
l_oBike.Stub(x => x.TypeOfBike).Return(TypeOfBike.Citybike);
l_oBike.Stub(x => x.Description).Return("MeinStadtrad");
l_oBike.Stub(x => x.Id).Return("22");
Assert.AreEqual(
"MeinStadtrad",
l_oBike.GetDisplayName());
Assert.AreEqual(
"22",
l_oBike.GetDisplayId());
l_oBike = MockRepository.GenerateStub<IBikeInfoMutable>();
l_oBike.Stub(x => x.WheelType).Return(WheelType.Two);
l_oBike.Stub(x => x.TypeOfBike).Return(TypeOfBike.Citybike);
l_oBike.Stub(x => x.Id).Return("22");
l_oBike.Stub(x => x.IsDemo).Return(true);
l_oBike.Stub(x => x.Description).Return("MeinStadtrad");
Assert.AreEqual(
"MeinStadtrad",
l_oBike.GetDisplayName());
Assert.AreEqual(
"22",
l_oBike.GetDisplayId());
l_oBike = MockRepository.GenerateStub<IBikeInfoMutable>();
l_oBike.Stub(x => x.WheelType).Return(WheelType.Trike);
l_oBike.Stub(x => x.TypeOfBike).Return(TypeOfBike.Cargo);
l_oBike.Stub(x => x.Description).Return("MeinCargoDreiradl");
l_oBike.Stub(x => x.Id).Return("22");
Assert.AreEqual(
"MeinCargoDreiradl",
l_oBike.GetDisplayName());
Assert.AreEqual(
"22",
l_oBike.GetDisplayId());
l_oBike = MockRepository.GenerateStub<IBikeInfoMutable>();
l_oBike.Stub(x => x.WheelType).Return(WheelType.Two);
l_oBike.Stub(x => x.TypeOfBike).Return(TypeOfBike.Cargo);
l_oBike.Stub(x => x.Description).Return("MeinCargoALololong");
l_oBike.Stub(x => x.Id).Return("22");
Assert.AreEqual(
"MeinCargoALololong",
l_oBike.GetDisplayName());
Assert.AreEqual(
"22",
l_oBike.GetDisplayId());
}
[Test]
public void TestGetDisplayName_UndefinedTypes()
{
var l_oBike = MockRepository.GenerateStub<IBikeInfoMutable>();
l_oBike.Stub(x => x.WheelType).Return(WheelType.Mono);
l_oBike.Stub(x => x.TypeOfBike).Return(TypeOfBike.Cargo);
l_oBike.Stub(x => x.Description).Return("SuperCargo");
l_oBike.Stub(x => x.Id).Return("22");
Assert.AreEqual(
"SuperCargo",
l_oBike.GetDisplayName());
Assert.AreEqual(
"22",
l_oBike.GetDisplayId());
}
}
}