using System; using System.Threading.Tasks; using NSubstitute; using NUnit.Framework; using TINK.Model.Bikes.BikeInfoNS.BluetoothLock; using TINK.Model.Connector; using TINK.Model.Device; using TINK.Model.State; using TINK.Model.User; using TINK.Repository.Exception; using TINK.Services.BluetoothLock; using TINK.Services.BluetoothLock.Exception; using TINK.Services.BluetoothLock.Tdo; using TINK.Services.Geolocation; using TINK.View; using TINK.ViewModel; using TINK.ViewModel.Bikes; using TINK.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler; namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler { [TestFixture] public class TestBookedDisconnected { /// /// Test construction of object. /// [Test] public void Testctor() { var handler = new BookedDisconnected( Substitute.For(), () => true, // isConnectedDelegate (isConnexted) => Substitute.For(), Substitute.For(), Substitute.For(), () => Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For(), Substitute.For()); // 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(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), 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); } /// /// Use case: Search. /// Final state: Booked open /// [Test] public void TestSearch() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var timeOuts = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks.ConnectAsync(Arg.Any(), Arg.Any()) .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(), Arg.Any()); 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); } /// /// Use case: Search. /// Final state: Booked unknown /// [Test] public void TestSearchCalculateAuthKeysFailsWebConnectFailureException() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), 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.UnknownFromHardwareError); 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("Error when connecting with lock!", "Internet must be reachable to connect to lock of rented bike.\r\nContext info\r\nIs WIFI available/ mobile networt available and mobile data activated / ... ?", "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); } /// /// Use case: Search. /// Final state: Booked unknown /// [Test] public void TestSearchCalculateAuthKeysFailsException() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), 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.UnknownFromHardwareError); 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("Error when connecting with lock!", "Communication error during lock search.\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); } /// /// Use case: Search. /// Final state: Booked unknown /// [Test] public void TestSearchConnectFailsOutOfReachException() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var timeOuts = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks.ConnectAsync(Arg.Any(), Arg.Any()) .Returns>(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(), Arg.Any()); bikesViewModel.ActionText = ""; viewService.DisplayAlert( "Error when connecting with lock!", "Lock can only be found when rented bike is nearby.", "Retry", "Cancel"); 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); } /// /// Use case: Search. /// Final state: Booked unknown /// [Test] public void TestSearchConnectFailsException() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var timeOuts = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks.ConnectAsync(Arg.Any(), Arg.Any()) .Returns>(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(), Arg.Any()); bikesViewModel.ActionText = ""; viewService.DisplayAdvancedAlert( "Error when connecting with lock!", "Your mobile device does not connect to the bike lock. Please step as close as possible to the bike and try again.", "", "Retry", "Cancel"); 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); } /// /// Use case: Search. /// Final state: Booked unknown /// [Test] public void TestSearchConnectNotOpen() { var bike = Substitute.For(); var connector = Substitute.For(); var command = Substitute.For(); var geolocation = Substitute.For(); var locks = Substitute.For(); var pollingManager = Substitute.For(); var viewService = Substitute.For(); var bikesViewModel = Substitute.For(); var activeUser = Substitute.For(); var timeOuts = Substitute.For(); var handler = new BookedDisconnected( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks.ConnectAsync(Arg.Any(), Arg.Any()) .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(), Arg.Any()); bikesViewModel.ActionText = ""; viewService.DisplayAlert("Error when connecting with lock!", "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); } } }