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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; connector.Command.CalculateAuthKeys(bike); bikesViewModel.ActionText = "Searching lock..."; locks.ConnectAsync(Arg.Any(), Arg.Any()); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.AreEqual("Close lock", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual(string.Empty, subsequent.LockitButtonText); Assert.That(subsequent.IsLockitButtonVisible, Is.False); } /// /// 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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; bikesViewModel.ActionText = string.Empty; viewService.DisplayAlert( "Connection to booking system not possible.", "A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.", "OK" ); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; bikesViewModel.ActionText = string.Empty; viewService.DisplayAlert("Connection to the lock could not be established.", "Exception message.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; connector.Command.CalculateAuthKeys(bike); bikesViewModel.ActionText = "Searching lock..."; locks.ConnectAsync(Arg.Any(), Arg.Any()); bikesViewModel.ActionText = string.Empty; viewService.DisplayAlert( "Connection to the lock could not be established.", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; connector.Command.CalculateAuthKeys(bike); bikesViewModel.ActionText = "Searching lock..."; locks.ConnectAsync(Arg.Any(), Arg.Any()); bikesViewModel.ActionText = string.Empty; viewService.DisplayAdvancedAlert( "Connection to the lock could not be established.", "Please step as close as possible to the bike lock and try again.", "", "Retry", "Cancel"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.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 behavior Received.InOrder(() => { bikesViewModel.Received(1).IsIdle = false; // GUI must be locked bikesViewModel.ActionText = "One moment please..."; pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action bikesViewModel.ActionText = "Request server..."; connector.Command.CalculateAuthKeys(bike); bikesViewModel.ActionText = "Searching lock..."; locks.ConnectAsync(Arg.Any(), Arg.Any()); bikesViewModel.ActionText = string.Empty; viewService.DisplayAlert("Connection to the lock could not be established.", "Lock status could not be determined. Please contact customer support.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartAsync(); // polling must be restarted again bikesViewModel.ActionText = string.Empty; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state after action Assert.AreEqual("BookedDisconnected", handler.ButtonText); Assert.IsFalse(handler.IsButtonVisible); Assert.AreEqual("Search lock", handler.LockitButtonText); Assert.IsTrue(handler.IsLockitButtonVisible); } } }