using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using NSubstitute; using NSubstitute.ExceptionExtensions; using NUnit.Framework; using Plugin.BLE.Abstractions.Contracts; using TestFramework.Model.Device; using TestFramework.Model.Services.Geolocation; using TestFramework.Model.User.Account; using TestFramework.Repository; using TestFramework.Services.CopriApi.Connector; using TINK.Model; using TINK.Model.Connector; using TINK.Model.Device; using TINK.Model.Services.CopriApi; using TINK.Model.Settings; using TINK.Repository; using TINK.Repository.Exception; using TINK.Services; using TINK.Services.BluetoothLock; using TINK.Services.BluetoothLock.Tdo; using TINK.Services.Geolocation; using TINK.Services.Permissions; using TINK.View; using TINK.ViewModel.BikesAtStation; using TINK.ViewModel.Map; using TINK.ViewModel.Settings; using Xamarin.Forms; using static TINK.Repository.CopriCallsMemory; namespace TestTINKLib.Fixtures.ObjectTests.ViewModel { [TestFixture] public class TestBikesAtStationPageViewModel { [Test] public async Task TestConstruct_Droid_NotLoggedIn() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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("", null, false, null, new List())), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("FR103", new List(), null), // Was station id 103 before switching from data provider CopriCallsMemory(SampleSets.ShareeFr01_Set1, 1, ...) () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.IsEmpty(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(2, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bikeFR9999 = bikesAtStation.FirstOrDefault(x => x.Id == "FR9999") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; // Was id 1315 var bikeFR9998 = bikesAtStation.FirstOrDefault(x => x.Id == "FR9998") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; // Was id 1543 Assert.That( bikeFR9999, Is.Not.Null); Assert.That( bikeFR9998, Is.Not.Null); Assert.AreEqual("Available.", bikeFR9999.StateText); Assert.AreEqual("Available.", bikeFR9998.StateText); Assert.AreEqual("NotLoggedIn", bikeFR9999.LockitButtonText); Assert.AreEqual("NotLoggedIn", bikeFR9998.LockitButtonText); // Login hint/ no bikes frame Assert.IsTrue(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid_NoBikes() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("102", new List(), null), // Station 102 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.IsEmpty(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(0, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsFalse(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsTrue(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual("Momentan sind keine Fahrräder an dieser Station verfügbar.", bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); // Fake location permissions to be set permissions.CheckStatusAsync().Returns(Task.FromResult(Status.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>(), Arg.Any()).Returns( new List { { new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() }, { new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() } } ); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: MERCH_ID, // Instance geolocation mocks both parts bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("103", new List(), null), // Station 103 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); // Verify behaviour Received.InOrder(() => { permissions.CheckStatusAsync(); var glDummy = geolocation.Active.Received().IsGeolcationEnabled; var btDummy = bluetooth.Received().State; locksService.GetLocksStateAsync(Arg.Any>(), Arg.Any()); }); Assert.IsEmpty(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bike1545 = bikesAtStation.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1537 = bikesAtStation.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1315 = bikesAtStation.FirstOrDefault(x => x.Id == "1315") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1543 = bikesAtStation.FirstOrDefault(x => x.Id == "1543") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; Assert.That( bike1545, Is.Not.Null); Assert.That( bike1537, Is.Not.Null); Assert.That( bike1315, Is.Not.Null); Assert.That( bike1543, Is.Not.Null); Assert.AreEqual($"Rented since {DateTime.Parse("2020-11-06 17:53:22.784681+01"):dd. MMMM HH:mm}.", bike1545.StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2020-10-12 08:38:12.374231+02"):dd. MMMM HH:mm}.", bike1537.StateText); Assert.AreEqual("Available.", bike1315.StateText); Assert.AreEqual("Available.", bike1543.StateText); Assert.AreEqual("Close lock", bike1545.LockitButtonText); Assert.AreEqual("Open lock", bike1537.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1315.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1543.LockitButtonText); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid_NoPermissions_OpenSettings() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); // Fake location permissions not to be set permissions.CheckStatusAsync().Returns(Task.FromResult(Status.Denied)); // Fake anwser on question whether to open permissions dialog viewService.DisplayAlert(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()).Returns(true); // Fake bluetooth answer for locks with id 2200545 and 2200537. locksService.GetLocksStateAsync(Arg.Any>(), Arg.Any()).Returns( new List { { new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() }, { new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() } } ); bluetooth.State.Returns(BluetoothState.On); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: MERCH_ID, bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("103", new List(), null), // Station 103 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); // Verify behaviour Received.InOrder(() => { permissions.CheckStatusAsync(); var glDummy = geolocation.Active.Received().IsGeolcationEnabled; // permissions.RequestAsync(); // Ask user from permissions (disabled, since no secondary request allowed). viewService.DisplayAlert( "Hint", "Please allow location sharing so that bike lock/locks can be managed.\r\nOpen sharing dialog?", "Yes", "No"); permissions.OpenAppSettings(); }); Assert.IsTrue(new List { "Updating...", string.Empty }.Contains(bikesAtStation.StatusInfoText)); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bike1545 = bikesAtStation.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1537 = bikesAtStation.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1315 = bikesAtStation.FirstOrDefault(x => x.Id == "1315") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1543 = bikesAtStation.FirstOrDefault(x => x.Id == "1543") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; Assert.That( bike1545, Is.Not.Null); Assert.That( bike1537, Is.Not.Null); Assert.That( bike1315, Is.Not.Null); Assert.That( bike1543, Is.Not.Null); Assert.AreEqual($"Rented since {DateTime.Parse("2020-11-06 17:53:22.784681+01"):dd. MMMM HH:mm}.", bike1545.StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2020-10-12 08:38:12.374231+02"):dd. MMMM HH:mm}.", bike1537.StateText); Assert.AreEqual("Available.", bike1315.StateText); Assert.AreEqual("Available.", bike1543.StateText); Assert.AreEqual("Search lock", bike1545.LockitButtonText); Assert.AreEqual("Search lock", bike1537.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1315.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1543.LockitButtonText); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid_NoPermissions() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); // Fake location permissions not to be set permissions.CheckStatusAsync().Returns(Task.FromResult(Status.Denied)); permissions.OpenAppSettings().Throws(); // Ensures that method is not called and fixture succeeds. // Fake anwser on question whether to open permissions dialog viewService.DisplayAlert(Arg.Any(), Arg.Any(), Arg.Any(), Arg.Any()).Returns(false); // Fake bluetooth answer for locks with id 2200545 and 2200537. locksService.GetLocksStateAsync(Arg.Any>(), Arg.Any()).Returns( new List { { new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() }, { new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() } } ); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: MERCH_ID, bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("103", new List(), null), // Station 103 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); // Verify behaviour Received.InOrder(() => { permissions.CheckStatusAsync(); var glDummy = geolocation.Active.Received().IsGeolcationEnabled; //permissions.RequestAsync(); // Ask user from permissions (disabled, since no secondary request allowed). viewService.DisplayAlert( "Hint", "Please allow location sharing so that bike lock/locks can be managed.\r\nOpen sharing dialog?", "Yes", "No"); }); Assert.IsEmpty(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bike1545 = bikesAtStation.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1537 = bikesAtStation.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1315 = bikesAtStation.FirstOrDefault(x => x.Id == "1315") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1543 = bikesAtStation.FirstOrDefault(x => x.Id == "1543") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; Assert.That( bike1545, Is.Not.Null); Assert.That( bike1537, Is.Not.Null); Assert.That( bike1315, Is.Not.Null); Assert.That( bike1543, Is.Not.Null); Assert.AreEqual($"Rented since {DateTime.Parse("2020-11-06 17:53:22.784681+01"):dd. MMMM HH:mm}.", bike1545.StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2020-10-12 08:38:12.374231+02"):dd. MMMM HH:mm}.", bike1537.StateText); Assert.AreEqual("Available.", bike1315.StateText); Assert.AreEqual("Available.", bike1543.StateText); Assert.AreEqual("Search lock", bike1545.LockitButtonText); Assert.AreEqual("Search lock", bike1537.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1315.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1543.LockitButtonText); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid_GeolocationOff() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); // Fake location permissions to be set permissions.CheckStatusAsync().Returns(Task.FromResult(Status.Granted)); geolocation.Active.IsGeolcationEnabled.Returns(false); // Fake gps to be off bluetooth.State.Returns(BluetoothState.On); // Fake bluetooth to be on // Fake bluetooth answer for locks with id 2200545 and 2200537. locksService.GetLocksStateAsync(Arg.Any>(), Arg.Any()).Returns( new List { { new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() }, { new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() } } ); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: MERCH_ID, bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("103", new List(), null), // Station 103 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); // Verify behaviour Received.InOrder(() => { permissions.CheckStatusAsync(); var glDummy = geolocation.Active.Received().IsGeolcationEnabled; viewService.DisplayAlert( "Hint", "Please activate location so that bike lock can be found!", "OK"); }); Assert.IsEmpty(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bike1545 = bikesAtStation.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1537 = bikesAtStation.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1315 = bikesAtStation.FirstOrDefault(x => x.Id == "1315") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1543 = bikesAtStation.FirstOrDefault(x => x.Id == "1543") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; Assert.That( bike1545, Is.Not.Null); Assert.That( bike1537, Is.Not.Null); Assert.That( bike1315, Is.Not.Null); Assert.That( bike1543, Is.Not.Null); Assert.AreEqual($"Rented since {DateTime.Parse("2020-11-06 17:53:22.784681+01"):dd. MMMM HH:mm}.", bike1545.StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2020-10-12 08:38:12.374231+02"):dd. MMMM HH:mm}.", bike1537.StateText); Assert.AreEqual("Available.", bike1315.StateText); Assert.AreEqual("Available.", bike1543.StateText); Assert.AreEqual("Search lock", bike1545.LockitButtonText); Assert.AreEqual("Search lock", bike1537.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1315.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1543.LockitButtonText); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Droid_BluetoothOff() { var geolocation = Substitute.For>(); var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); // Fake location permissions to be set permissions.CheckStatusAsync().Returns(Task.FromResult(Status.Granted)); geolocation.Active.IsGeolcationEnabled.Returns(true); // Fake gps to be on bluetooth.State.Returns(BluetoothState.Off); // // Fake bluetooth to be off // Fake bluetooth answer for locks with id 2200545 and 2200537. locksService.GetLocksStateAsync(Arg.Any>(), Arg.Any()).Returns( new List { { new LockInfoTdo.Builder { Id = 2200545, State = LockitLockingState.Open }.Build() }, { new LockInfoTdo.Builder { Id = 2200537, State = LockitLockingState.Closed }.Build() } } ); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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", false, "5781_d47fc786e740ef77d85a24bcb6f0ff97_oiF2kahH", new List { "300001", "300029" })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.ShareeFr01_Set1, 1, sessionCookie)), merchantId: MERCH_ID, bluetoothService: Substitute.For(), locationPermissionsService: null, locationServicesContainer: geolocation, locksService: locksService, // Cipher device: new DeviceMock(), // Permissions, specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.Android, new TINK.Model.Station.Station("103", new List(), null), // Station 103 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), geolocation.Active, // geolocation locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); // Verify behaviour Received.InOrder(() => { permissions.CheckStatusAsync(); 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(bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); var bike1545 = bikesAtStation.FirstOrDefault(x => x.Id == "1545") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1537 = bikesAtStation.FirstOrDefault(x => x.Id == "1537") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1315 = bikesAtStation.FirstOrDefault(x => x.Id == "1315") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; var bike1543 = bikesAtStation.FirstOrDefault(x => x.Id == "1543") as TINK.ViewModel.Bikes.Bike.BluetoothLock.BikeViewModel; Assert.That( bike1545, Is.Not.Null); Assert.That( bike1537, Is.Not.Null); Assert.That( bike1315, Is.Not.Null); Assert.That( bike1543, Is.Not.Null); Assert.AreEqual($"Rented since {DateTime.Parse("2020-11-06 17:53:22.784681+01"):dd. MMMM HH:mm}.", bike1545.StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2020-10-12 08:38:12.374231+02"):dd. MMMM HH:mm}.", bike1537.StateText); Assert.AreEqual("Available.", bike1315.StateText); Assert.AreEqual("Available.", bike1543.StateText); Assert.AreEqual("Search lock", bike1545.LockitButtonText); Assert.AreEqual("Search lock", bike1537.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1315.LockitButtonText); Assert.AreEqual("DisposableDisconnected", bike1543.LockitButtonText); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstructKonrad() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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(), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo(MERCH_ID, "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), merchantId: MERCH_ID, bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("FR101", new List(), null), // Was 31 before switching CopriCallsMemory(SampleSets.Set2, 1, ...) () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.IsTrue(new List { "Updating...", string.Empty }.Contains(bikesAtStation.StatusInfoText)); // Verify list of bikes Assert.AreEqual(3, bikesAtStation.Count); // Was 1 before switch. Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR1003").StateText); // Was 52 before switch. Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR1002").StateText); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR1001").StateText); // Login hint/ no bikes frame Assert.IsTrue(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstructKonrad_NoBikes() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); const string MERCH_ID = "MyMerchId"; var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), new Uri("https://tinkwwp.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(), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory(MERCH_ID, SampleSets.Set2, 1, sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("4", new List(), null), () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.IsTrue(new List { "Updating...", string.Empty }.Contains(bikesAtStation.StatusInfoText)); // Verify list of bikes Assert.AreEqual(0, bikesAtStation.Count); Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsFalse(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsTrue(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual("Momentan sind keine Fahrräder an dieser Station verfügbar.", bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_LoggedIn() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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: locksService.GetType().FullName), new StoreMock(new TINK.Model.User.Account.Account( LoginSessionCopriInfo.JavaministerHardwareNr1.Mail, LoginSessionCopriInfo.JavaministerHardwareNr1.Pwd, false, "6103_112e96b36ba33de245943c5ffaf369cd_", // Was 4da3044c8657a04ba60e2eaa753bc51a before switching from data provider CopriCallsMemory(SampleSets.Set2, 1, ...) new List { FilterHelper.CARGOBIKE })), isConnectedFunc: () => true, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("FR103", new List(), null), // Was station id 4 before switching from data provider CopriCallsMemory(SampleSets.Set2, 1, ...) () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.IsTrue(new List { "Updating...", string.Empty }.Contains(bikesAtStation.StatusInfoText)); // Verify list of bikes Assert.AreEqual(4, bikesAtStation.Count); // Count of bikes was 4 before switching from data provider CopriCallsMemory(SampleSets.Set2, 1, ...) Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9999").StateText); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9999").StateText); Assert.AreEqual("Max. reservation time of 15 min. expired.", bikesAtStation.FirstOrDefault(x => x.Id == "FR1004").StateText); Assert.AreEqual($"Rented since {DateTime.Parse("2021-11-06 18:57:25.445447+01"):dd. MMMM HH:mm}.", bikesAtStation.FirstOrDefault(x => x.Id == "FR1544").StateText); // Was 7 // Login hint/ no bikes frame Assert.IsFalse(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_Offline() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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(), isConnectedFunc: () => false, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(new AppContextInfo("MyMerchId", "MyApp", new Version(1, 2)), null /*UI language */, sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, // Not connected. theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("FR103", new List(), null), // Was station id 4 before switching from data provider CopriCallsMemory(SampleSets.Set2, 1 () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService); await bikesAtStation.OnAppearing(); Assert.AreEqual("Offline.", bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(2, bikesAtStation.Count); // Count of bikes was 3. There is no more bike with id 26. Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9999").StateText); // Was id 5 Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9998").StateText); // Was is 14 // Login hint/ no bikes frame Assert.IsTrue(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestConstruct_WebConnectCommunicationError() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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(), isConnectedFunc: () => false, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector( uri, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie, mail, server: new CopriProviderHttps( uri, TinkApp.MerchantId, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory001(sessionCookie: sessionCookie), httpsServer: new ExceptionServer((msg) => new WebConnectFailureException(msg, new Exception("Source expection."))))), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, // Not connected. theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("FR103", new List(), null), // Was station id 4 before switching from data provider CopriCallsCacheMemory() () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService) { IsReportLevelVerbose = true }; await bikesAtStation.OnAppearing(); Assert.AreEqual("Connection interrupted, server unreachable.", bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(2, bikesAtStation.Count); // Count of bikes was 3. There is no more bike with id 26. Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9999").StateText); // Was id 5 Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9998").StateText); // Was is 14 // Login hint/ no bikes frame Assert.IsTrue(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } [Test] public async Task TestTinkApp_GeneralPurposeError() { var locksService = Substitute.For(); var timeOut = Substitute.For(); var viewService = Substitute.For(); var permissions = Substitute.For(); var bluetooth = Substitute.For(); bluetooth.State.Returns(BluetoothState.On); locksService.TimeOut.Returns(timeOut); timeOut.MultiConnect.Returns(new TimeSpan(0)); var tinkApp = new TinkApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.On }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), 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(), isConnectedFunc: () => false, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector( uri, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie, mail, server: new CopriProviderHttps( uri, TinkApp.MerchantId, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory001(sessionCookie: sessionCookie), httpsServer: new ExceptionServer((msg) => new Exception(msg)))), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: locksService, // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, // Not connected. theme: null, 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 bikesAtStation = new BikesAtStationPageViewModel( tinkApp.ActiveUser, permissions, bluetooth, Device.iOS, new TINK.Model.Station.Station("FR103", new List(), null), // Was station id 4 before switching from data provider CopriCallsCacheMemory() () => tinkApp.GetIsConnected(), (isConnected) => tinkApp.GetConnector(isConnected), new GeolocationMock(), locksService, tinkApp.Polling, (url) => { }, (d, obj) => d(obj), Substitute.For(), viewService) { IsReportLevelVerbose = true }; await bikesAtStation.OnAppearing(); Assert.AreEqual("Connection interrupted.", bikesAtStation.StatusInfoText); // Verify list of bikes Assert.AreEqual(2, bikesAtStation.Count); // Count of bikes was 3. There is no more bike with id 26. Assert.IsTrue(bikesAtStation.IsIdle); Assert.IsTrue(bikesAtStation.IsBikesListVisible, "If there are any bikes, list must be visible."); Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9999").StateText); // Was id 5 Assert.AreEqual("Available.", bikesAtStation.FirstOrDefault(x => x.Id == "FR9998").StateText); // Was id 14. // Login hint/ no bikes frame Assert.IsTrue(bikesAtStation.IsLoginRequiredHintVisible); Assert.IsFalse(bikesAtStation.IsNoBikesAtStationVisible); Assert.AreEqual(string.Empty, bikesAtStation.NoBikesAtStationText); } } }