using System; using System.Threading.Tasks; using Newtonsoft.Json; 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.Repository.Request; using TINK.Repository.Response; 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 TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler { [TestFixture] public class TestBookedUnknown { /// /// Test construction of object. /// [Test] public void Testctor() { var handler = new BookedUnknown( 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("Open lock", handler.ButtonText); Assert.IsTrue(handler.IsButtonVisible); Assert.AreEqual("Close lock", handler.LockitButtonText); Assert.IsTrue(handler.IsLockitButtonVisible); } /// /// Use case: Opens lock /// Final state: Booked opened. /// [Test] public void TestOpen() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success bike.State.Value.Returns(InUseStateEnum.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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed 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 "Booked Closed" 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: Open lock /// Final state: Same as initial state. /// [Test] public void TestOpenOpenFailsOutOfReachException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns>(x => throw new OutOfReachException()); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Closed); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = ""; viewService.DisplayAlert("Error while opening lock!", "Lock cannot be opened 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 "Booked Disconnected" after action Assert.AreEqual(nameof(BookedDisconnected), subsequent.ButtonText); Assert.IsFalse(subsequent.IsButtonVisible); Assert.AreEqual("Search lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Open lock /// Final state: Same as initial state. /// [Test] public void TestOpenOpenFailsCouldntOpenBoldBlockedException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns>(x => throw new CouldntOpenBoldIsBlockedException()); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Closed); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = ""; viewService.DisplayAlert("Error while opening lock!", "Lock is blocked. Please ensure that no obstacle prevents lock from opening and try again.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Unknown" after action Assert.AreEqual("Open lock", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Close lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Open lock /// Final state: Same as initial state. /// [Test] public void TestOpenOpenFailsCouldntOpenInconsistentStateExecptionClosed() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns>(x => throw new CouldntOpenInconsistentStateExecption(LockingState.Closed)); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Closed); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = ""; viewService.DisplayAlert("Error while opening lock!", "After try to open lock state closed is reported.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" after action Assert.AreEqual("Return bike", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Open lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Open lock /// Final state: Same as initial state. /// [Test] public void TestOpenOpenFailsCouldntOpenInconsistentStateExecption() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns>(x => throw new CouldntOpenBoldWasBlockedException()); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Closed); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = ""; viewService.DisplayAlert("Lock can not be opened!", "Lock was blocked and might still be. Please ensure that no obstacle prevents lock from opening and try again.", "OK"); bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Disconnected" after action Assert.AreEqual("Open lock", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Close lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Open lock /// Final state: Same as initial state. /// [Test] public void TestOpenOpenFailsException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns>(x => throw new Exception("Exception message.")); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Closed); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = ""; viewService.DisplayAlert("Error while opening lock!", "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 "Booked Disconnected" after action Assert.AreEqual(nameof(BookedDisconnected), subsequent.ButtonText); Assert.IsFalse(subsequent.IsButtonVisible); Assert.AreEqual("Search lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Opens lock /// Final state: Booked opened. /// [Test] public void TestOpenGetBatteryPercentageAsyncThrowsOutOfReachException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success locks[0].GetBatteryPercentageAsync().Returns>(x => throw new OutOfReachException()); bike.State.Value.Returns(InUseStateEnum.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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = "Reading charging level..."; locks[0].GetBatteryPercentageAsync(); bikesViewModel.ActionText = "Battery status can only be read when bike is nearby."; 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 "Booked Closed" 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: Opens lock /// Final state: Booked opened. /// [Test] public void TestOpenGetBatteryPercentageAsyncThrowsExcepton() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Open)); // Return lock state indicating success locks[0].GetBatteryPercentageAsync().Returns>(x => throw new Exception()); bike.State.Value.Returns(InUseStateEnum.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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = "Reading charging level..."; locks[0].GetBatteryPercentageAsync(); bikesViewModel.ActionText = "Battery status cannot be read."; 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 "Booked Closed" 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: Open lock /// Final state: Booked open. /// [Test] public void TestOpenUpdateLockingStateFailsWebConnectFailureException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(LockitLockingState.Open); connector.Command.UpdateLockingStateAsync(bike, null).Returns(x => throw new WebConnectFailureException("Context info", new System.Exception("hoppla"))); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = "Reading charging level..."; locks[0].GetBatteryPercentageAsync(); bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, null); bikesViewModel.ActionText = "No web error on updating locking status."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" 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: Open lock /// Final state: Booked open. /// [Test] public void TestOpenUpdateLockingStateFailsException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(LockitLockingState.Open); connector.Command.UpdateLockingStateAsync(bike, Arg.Any()).Returns(x => throw new Exception("Exception message.")); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = "Reading charging level..."; locks[0].GetBatteryPercentageAsync(); bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, Arg.Any()); bikesViewModel.ActionText = "Connection error on updating locking status."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" 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: Open lock /// Final state: Booked open. /// [Test] public void TestOpenUpdateLockingStateFailsResponseException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].OpenAsync() .Returns(LockitLockingState.Open); connector.Command.UpdateLockingStateAsync(bike, Arg.Any()).Returns(x => throw new ReturnBikeException(JsonConvert.DeserializeObject(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message.")); 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 = "Opening lock..."; locks.Received()[0].OpenAsync(); // Lock must be closed bikesViewModel.ActionText = "Reading charging level..."; locks[0].GetBatteryPercentageAsync(); bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, Arg.Any()); bikesViewModel.ActionText = "Status error on updating lock state."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" 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: Close lock /// Final state: Booked closed. /// [Test] public void TestClose() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed)); // Return lock state indicating success 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, 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 "Booked Closed" after action Assert.AreEqual("Return bike", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Open lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Close lock /// Final state: Same as initial state. /// [Test] public void TestCloseCloseFailsOutOfReachException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns>(x => throw new OutOfReachException()); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Open); 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed 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 "Booked disconnected" after action Assert.AreEqual("BookedDisconnected", subsequent.ButtonText); Assert.IsFalse(subsequent.IsButtonVisible); Assert.AreEqual("Search lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Close lock /// Final state: Same as initial state. /// [Test] public void TestCloseCloseFailsException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns>(x => throw new Exception("Exception message.")); bike.State.Value.Returns(InUseStateEnum.Booked); bike.LockInfo.State.Returns(LockingState.Open); 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed 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 "Booked Disconnected" after action Assert.AreEqual("BookedDisconnected", subsequent.ButtonText); Assert.IsFalse(subsequent.IsButtonVisible); Assert.AreEqual("Search lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: Close lock /// Final state: Booked closed. /// [Test] public void TestCloseUpdateLockingStateFailsWebConnectFailureException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns(LockitLockingState.Closed); // Return lock state indicating success connector.Command.UpdateLockingStateAsync(bike, Arg.Any()).Returns(x => throw new WebConnectFailureException("Context info", new System.Exception("hoppla"))); 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, Arg.Any()); bikesViewModel.ActionText = "No web error on updating locking status."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" after action Assert.AreEqual("Return bike", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Open lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: close lock /// Final state: Booked closed. /// [Test] public void TestCloseUpdateLockingStateFailsException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns(LockitLockingState.Closed); // Return lock state indicating success connector.Command.UpdateLockingStateAsync(bike, Arg.Any()).Returns(x => throw new Exception("Exception message.")); 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, Arg.Any()); bikesViewModel.ActionText = "Connection error on updating locking status."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" after action Assert.AreEqual("Return bike", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Open lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } /// /// Use case: close lock /// Final state: Booked closed. /// [Test] public void TestCloseUpdateLockingStateFailsResponseException() { 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 BookedUnknown( bike, () => true, // isConnectedDelegate (isConnexted) => connector, geolocation, locks, () => pollingManager, Substitute.For(), viewService, bikesViewModel, activeUser); locks[0].CloseAsync() .Returns(LockitLockingState.Closed); // Return lock state indicating success connector.Command.UpdateLockingStateAsync(bike, Arg.Any()).Returns(x => throw new ReturnBikeException(JsonConvert.DeserializeObject(@"{ ""response_text"" : ""Some invalid data received!""}"), "Outer message.")); 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 = "Closing lock..."; locks.Received()[0].CloseAsync(); // Lock must be closed bikesViewModel.ActionText = "Updating lock state..."; connector.Command.UpdateLockingStateAsync(bike, Arg.Any()); bikesViewModel.ActionText = "Status error on updating lock state."; bikesViewModel.ActionText = "Updating..."; pollingManager.StartUpdateAyncPeridically(); // polling must be restarted again bikesViewModel.ActionText = ""; bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked }); // Verify state "Booked Closed" after action Assert.AreEqual("Return bike", subsequent.ButtonText); Assert.IsTrue(subsequent.IsButtonVisible); Assert.AreEqual("Open lock", subsequent.LockitButtonText); Assert.IsTrue(subsequent.IsLockitButtonVisible); } } }