using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using NSubstitute; using NUnit.Framework; using Plugin.BLE.Abstractions.Contracts; using SharedBusinessLogic.Tests.Framework.Model.Device; using SharedBusinessLogic.Tests.Framework.Model.Services.Geolocation; using SharedBusinessLogic.Tests.Framework.Model.User.Account; using SharedBusinessLogic.Tests.Framework.Repository; using SharedBusinessLogic.Tests.Framework.Services.BluetoothLock; using ShareeBike.Model; using ShareeBike.Model.Bikes.BikeInfoNS.BluetoothLock; using ShareeBike.Model.Bikes.BikeInfoNS.BikeNS; using ShareeBike.Model.Bikes.BikeInfoNS.DriveNS; using ShareeBike.Model.Connector; using ShareeBike.Model.Services.CopriApi; using ShareeBike.Model.Settings; using ShareeBike.Model.Stations.StationNS; using ShareeBike.Repository; using ShareeBike.Repository.Exception; using ShareeBike.Services; using ShareeBike.Services.Geolocation; using ShareeBike.Services.Permissions; using ShareeBike.View; using ShareeBike.ViewModel.Map; using ShareeBike.ViewModel.Settings; using Xamarin.Forms; using ShareeBike.Model.Bikes.BikeInfoNS; using ShareeBike.Model.Stations.StationNS.Operator; namespace SharedBusinessLogic.Tests.UseCases.Startup { [TestFixture] public class TestMapPageViewModel { [Test] public async Task TestConstruct() { var shareeBikeApp = new ShareeBikeApp( 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://tinkwwp.copri-bike.de/APIjsonserver"), new ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).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, server: new CopriCallsMemory001v2NotLoggedIn(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // 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 viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That(viewModel.Exception, Is.Null); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(27)); // Were 8 pins when loading from CopriCallsMemory(SampleSets.Set2, 1, sessionCookie) Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, Is.EqualTo("FR101"), "Station FR105 must be marked green because there are bikes."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, Is.EqualTo("KN12"), "Station KN12 must be marked red because there is no bike."); // Was station id 31 // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.True, "ShareeBike and Citybike are activated in settings."); Assert.That(viewModel.CargoColor, Is.EqualTo(Color.White), "ShareeBike bikes are shown."); Assert.That(viewModel.CitybikeColor, Is.EqualTo(Color.FromRgba(0, 0, 0, 0)), "Citybike bikes are hidden."); var statusInfoText = viewModel.StatusInfoText; Assert.That( statusInfoText, Does.Contain("Updating...").Or.Contain(""), "Unexpected text detected. Text might be \"Updating...\" or empty depending on activity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_CitybikeActive() { var shareeBikeApp = new ShareeBikeApp( 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 ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).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, server: new CopriCallsMemory001v2NotLoggedIn(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // 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 viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That(viewModel.Exception, Is.Null); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(21)); // Were 2 pins when loading from CopriCallsMemory(SampleSets.Set2, 1, sessionCookie) Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, // Was station 5 Is.EqualTo("FR103"), "Station FR101 must be marked green because there is are bike."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, // Was station 14 Is.EqualTo("KN12"), "Station KN12 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.True, "ShareeBike and Citybike are activated in settings."); Assert.That(viewModel.CargoColor, Is.EqualTo(Color.FromRgba(0, 0, 0, 0)), "ShareeBike bikes are hidden."); Assert.That(viewModel.CitybikeColor, Is.EqualTo(Color.White), "Citybike bikes are shown."); Assert.That( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), Is.True, "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_CitybikeOnly() { var shareeBikeApp = new ShareeBikeApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CITYBIKE, FilterState.On } }), new GroupFilterSettings(new Dictionary { { FilterHelper.CARGOBIKE, FilterState.Off }, { FilterHelper.CITYBIKE, FilterState.On } }), new StartupSettings(), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).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, server: new CopriCallsMemory001v2NotLoggedIn(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to var viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That(viewModel.Exception, Is.Null); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(21)); // Were 2 when loading from CopriCallsMemory(SampleSets.Set2, 1, sessionCookie) Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, // Was station id 31 Is.EqualTo("FR103"), "Station FR101 must be marked green because there is are bike."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, // Was 14 Is.EqualTo("KN12"), "Station KN12 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.False, "ShareeBike and Citybike is deactivated from settings."); Assert.That( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), Is.True, "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_CargoOnly() { var shareeBikeApp = new ShareeBikeApp( new Settings( new GroupFilterMapPage(new Dictionary { { FilterHelper.CARGOBIKE, 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 ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).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, server: new CopriCallsMemory001v2NotLoggedIn(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); var viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That(viewModel.Exception, Is.Null); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(27)); // Were 8 pin when loading from CopriCallsMemory(SampleSets.Set2, 1, sessionCookie) Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, Is.EqualTo("FR101"), // Was station id 4 "Station FR101 must be marked green because there is are bike."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, // Was 31 Is.EqualTo("KN12"), // Was station id 31 "Station KN12 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.False, "ShareeBike and Citybike is deactivated from settings."); Assert.That( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), Is.True, "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_Offline() { var shareeBikeApp = new ShareeBikeApp( 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://tinkwwp.copri-bike.de/APIjsonserver"), new ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).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, server: new CopriCallsMemory001v2NotLoggedIn(sessionCookie)), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to var viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That(viewModel.Exception, Is.Null); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(27)); // Were 8 pins when loading from CopriCallsMemory(SampleSets.Set2, 1, sessionCookie) Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, // Was station id 4 Is.EqualTo("FR101"), "Station FR101 must be marked green because there is are bike."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, // Was 31 Is.EqualTo("KN12"), "Station KN12 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.True, "ShareeBike and Citybike are activated in settings."); Assert.That(viewModel.CargoColor, Is.EqualTo(Color.White), "ShareeBike bikes are hidden."); Assert.That(viewModel.CitybikeColor, Is.EqualTo(Color.FromRgba(0, 0, 0, 0)), "Citybike bikes are shown."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_WebConnectCommunicationError() { var shareeBikeApp = new ShareeBikeApp( 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://tinkwwp.copri-bike.de/APIjsonserver"), new ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, true /* IsReportLevelVerbose */, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), isConnectedFunc: () => false, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new Connector( uri, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie, mail, server: new CopriProviderHttps( uri, ShareeBikeApp.MerchantId, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory001v2NotLoggedIn(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: new LocksServiceMock(), // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to var viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That( viewModel.Exception.Message, Is.EqualTo("Simulated error thrown at GetStationsAsync.")); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(27)); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Green"))?.Tag, // Was station id 4 Is.EqualTo("FR101"), "Station FR101 must be marked green because there is are bike."); Assert.That( viewModel.Pins.FirstOrDefault(pin => pin.Icon.Id.Contains("Open_Red"))?.Tag, // Was 31 Is.EqualTo("KN12"), "Station KN12 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.True, "ShareeBike and Citybike are activated in settings."); Assert.That(viewModel.CargoColor, Is.EqualTo(Color.White), "ShareeBike bikes are hidden."); Assert.That(viewModel.CitybikeColor, Is.EqualTo(Color.FromRgba(0, 0, 0, 0)), "Citybike bikes are shown."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_GeneralPurposeCommunicationError() { var shareeBikeApp = new ShareeBikeApp( 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://tinkwwp.copri-bike.de/APIjsonserver"), new ShareeBike.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, true /* IsReportLevelVerbose */, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), isConnectedFunc: () => false, connectorFactory: (isConnected, uri, sessionCookie, mail, expiresAfter) => new Connector( uri, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie, mail, server: new CopriProviderHttps( uri, ShareeBikeApp.MerchantId, new AppContextInfo("oiF2kahH", "sharee.bike.test", new Version(3, 0, 267)), null /*UI language */, sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory001v2NotLoggedIn(sessionCookie: sessionCookie), httpsServer: new ExceptionServer((msg) => new Exception(msg)))), merchantId: "MyMerchId", bluetoothService: Substitute.For(), locationPermissionsService: Substitute.For(), locationServicesContainer: Substitute.For>(), locksService: new LocksServiceMock(), // Cipher device: new DeviceMock(), specialFolder: new SpecialFolderMock(), cipher: null, theme: null, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to var viewService = Substitute.For(); var navigationService = Substitute.For(); var locationPermission = Substitute.For(); locationPermission.CheckStatusAsync().Returns(Status.Granted); var viewModel = new MapPageViewModel( shareeBikeApp, locationPermission, Substitute.For(), Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.That( viewModel.Exception.Message, Is.EqualTo("Simulated error thrown at GetStationsAsync.")); // Verify pins on map Assert.That(viewModel.Pins.Count, Is.EqualTo(27)); Assert.That( viewModel.Pins.Where(pin => pin.Icon.Id.Contains("Open_Green")).Select(pin => pin.Tag.ToString()), Does.Contain("FR101"), // Was station id 4 "Station FR103 must be marked green because there is are bike."); Assert.That( viewModel.Pins.Where(pin => pin.Icon.Id.Contains("Open_Red")).Select(pin => pin.Tag.ToString()), Does.Contain("KN12"), // Was station id 31 "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.That(viewModel.IsToggleVisible, Is.True, "ShareeBike and Citybike are activated in settings."); Assert.That(viewModel.CargoColor, Is.EqualTo(Color.White), "ShareeBike bikes are hidden."); Assert.That(viewModel.CitybikeColor, Is.EqualTo(Color.FromRgba(0, 0, 0, 0)), "Citybike bikes are shown."); } finally { await viewModel.OnDisappearing(); } } [Test] public void TestGetStationColors() { var stationIds = new List() { "FR101", "BVB9003", "BVB9001" }; var bikeGroupFr101 = Substitute.For(); var bikeGroupBVB9003 = Substitute.For(); var bikeGroupBVB9001 = Substitute.For(); bikeGroupFr101.AvailableCount.Returns(1); bikeGroupBVB9003.AvailableCount.Returns(7); bikeGroupBVB9001.AvailableCount.Returns(0); var stations = new List { new Station("FR101", new List() /* group */, Substitute.For(), bikeGropCol: bikeGroupFr101), new Station("BVB9003", new List() /* group */, Substitute.For(), bikeGropCol: bikeGroupBVB9003), new Station("BVB9001", new List() /* group */, Substitute.For(), bikeGropCol : bikeGroupBVB9001) }; var bikes = new List { // Add a reserved bike to station "FR101" new BikeInfo( new Bike("Id1", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 123, // Lock id new Guid(), new byte[0], new byte[0], new byte[0], DateTime.Parse("2023-03-26 15:19"), "a@b", "FR101", new Uri("https://1.2.3.4"), new RentalDescription(), () => DateTime.Now) }; var colorList = MapPageViewModel.GetStationColors(stationIds, stations, bikes); Assert.That(colorList[0], Is.EqualTo(Color.LightBlue), "1 bike reserved/ rented."); Assert.That(colorList[1], Is.EqualTo(Color.Green), "7 available bikes."); Assert.That(colorList[2], Is.EqualTo(Color.Red), "No bike"); } [Test] public void TestGetStationColorsNullIds() { var colorList = MapPageViewModel.GetStationColors(null, null, null); Assert.That(colorList.Count, Is.EqualTo(0)); } [Test] public void TestGetStationColorsNoStations() { var stationIds = new List() { "FR101", "BVB9003", "BVB9001" }; var bikes = new List { // Add a reserved bike to station "FR101" new BikeInfo( new Bike("Id1", LockModel.ILockIt), new DriveMutable(), ShareeBike.Model.Bikes.BikeInfoNS.BC.DataSource.Copri, 123, // Lock id new Guid(), new byte[0], new byte[0], new byte[0], DateTime.Parse("2023-03-26 15:19"), "a@b", "FR101", new Uri("https://1.2.3.4"), new RentalDescription(), () => DateTime.Now) }; var colorList = MapPageViewModel.GetStationColors(stationIds, null, bikes); Assert.That(colorList[0], Is.EqualTo(Color.LightBlue), "1 bike reserved/ rented."); Assert.That(colorList[1], Is.EqualTo(Color.Red), "No bike."); Assert.That(colorList[2], Is.EqualTo(Color.Red), "No bike"); } [Test] public void TestGetStationColorsNoBikes() { var stationIds = new List() { "FR101", "BVB9003", "BVB9001" }; var bikeGroupFr101 = Substitute.For(); var bikeGroupBVB9003 = Substitute.For(); var bikeGroupBVB9001 = Substitute.For(); bikeGroupFr101.AvailableCount.Returns(1); bikeGroupBVB9003.AvailableCount.Returns(7); bikeGroupBVB9001.AvailableCount.Returns(0); var stations = new List { new Station("FR101", new List() /* group */, Substitute.For(), bikeGropCol: bikeGroupFr101), new Station("BVB9003", new List() /* group */, Substitute.For(),bikeGropCol: bikeGroupBVB9003), new Station("BVB9001", new List() /* group */, Substitute.For(), bikeGropCol: bikeGroupBVB9001) }; var colorList = MapPageViewModel.GetStationColors(stationIds, stations, null); Assert.That(colorList[0], Is.EqualTo(Color.Green), "No bike reserved/ rented."); Assert.That(colorList[1], Is.EqualTo(Color.Green), "7 available bikes."); Assert.That(colorList[2], Is.EqualTo(Color.Red), "No bike"); } } }