using NUnit.Framework; using Rhino.Mocks; using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using TestTINKLib.Mocks.Connector; using TestTINKLib.Mocks.Device; using TestTINKLib.Mocks.Services; using TestTINKLib.Model.User.Account; using TINK.Model; using TINK.Model.Connector; using TINK.Repository.Exception; using TINK.Model.Services.CopriApi; using TINK.Repository; using TINK.View; using TINK.ViewModel.Map; using Xamarin.Forms; using static TINK.Repository.CopriCallsMemory; using TINK.ViewModel.Settings; using TINK.Model.Services.Geolocation; using TINK.Services; using NSubstitute; namespace TestTINKLib.Fixtures.UseCases.Startup { [TestFixture] public class TestMapPageViewModel { [Test] public async Task TestConstruct() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.Off } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => true, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.IsNull(viewModel.Exception); // Verify pins on map Assert.AreEqual(8, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"), "Station 4 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"), "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings."); Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are shown."); Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are hidden."); var statusInfoText = viewModel.StatusInfoText; Assert.That( statusInfoText, Does.Contain("Updating...").Or.Contain(""), $"Unexpected text {statusInfoText} detected.", "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_KonradActive() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => true, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.IsNull(viewModel.Exception); // Verify pins on map Assert.AreEqual(2, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Green"), "Station 5 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "14").Icon.Id.Contains("Red"), "Station 14 must be marked red because there is no bike."); // Verify buttons Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings."); Assert.AreEqual(Color.Gray, viewModel.TinkColor, "TINK bikes are hidden."); Assert.AreEqual(Color.Red, viewModel.KonradColor, "Konrad bikes are shown."); Assert.IsTrue( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_KonradOnly() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "Konrad", FilterState.On } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.Off }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => true, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.IsNull(viewModel.Exception); // Verify pins on map Assert.AreEqual(2, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Green"), "Station 5 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "14").Icon.Id.Contains("Red"), "Station 14 must be marked red because there is no bike."); // Verify buttons Assert.IsFalse(viewModel.IsToggleVisible, "TINK and Konrad is deactivated from settings."); Assert.IsTrue( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_TinkOnly() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.On } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => true, currentVersion: new Version(3, 2, 0, 115), // Current app version lastVersion: new Version(3, 0, 173)); var viewService = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.IsNull(viewModel.Exception); // Verify pins on map Assert.AreEqual(8, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"), "Station 4 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"), "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.IsFalse(viewModel.IsToggleVisible, "TINK and Konrad is deactivated from settings."); Assert.IsTrue( new[] { "Updating...", "" }.Contains(viewModel.StatusInfoText), "Text might be \"Updating...\" or empty depending on acivity of update thread."); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_Offline() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => false, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.IsNull(viewModel.Exception); // Verify pins on map Assert.AreEqual(8, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"), "Station 4 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"), "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings."); Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are hidden."); Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown."); Assert.AreEqual("Offline.", viewModel.StatusInfoText); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_WebConnectCommunicationError() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, true /* IsReportLevelVerbose */, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector( uri, "TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default", sessionCookie, mail, server: new CopriProviderHttps( uri, TinkApp.MerchantId, "TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default", sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie), httpsServer: new ExceptionServer((msg) => new WebConnectFailureException(msg, new Exception("Source expection."))))), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => false, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.AreEqual( "Simulated error thrown at GetStationsAsync.", viewModel.Exception.Message); // Verify pins on map Assert.AreEqual(8, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"), "Station 4 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"), "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings."); Assert.AreEqual(Color.Blue, viewModel.TinkColor, "TINK bikes are hidden."); Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown."); Assert.AreEqual("Connection interrupted, server unreachable.", viewModel.StatusInfoText); } finally { await viewModel.OnDisappearing(); } } [Test] public async Task TestConstruct_GeneralPurposeCommunicationError() { var tinkApp = new TinkApp( new TINK.Model.Settings.Settings( new GroupFilterMapPage(new Dictionary { { "TINK", FilterState.On }, { FilterHelper.FILTERKONRAD, FilterState.Off } }), new GroupFilterSettings(new Dictionary { { "TINK", FilterState.On }, { "Konrad", FilterState.On } }), new Uri("https://tinkwwp.copri-bike.de/APIjsonserver"), new TINK.Settings.PollingParameters(new TimeSpan(10000), true), Serilog.Events.LogEventLevel.Error, true /* IsReportLevelVerbose */, activeLockService: typeof(LocksServiceMock).FullName, activeGeolocationService: typeof(GeolocationMock).FullName), new StoreMock(), (isConnected, uri, sessionCookie, mail, expiresAfter) => new TINK.Model.Connector.Connector( uri, "TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default", sessionCookie, mail, server: new CopriProviderHttps( uri, TinkApp.MerchantId, "TestTINKApp/3.0.127 AutomatedTestEnvirnoment/Default", sessionCookie: sessionCookie, cacheServer: new CopriCallsCacheMemory(sessionCookie: sessionCookie), httpsServer: new ExceptionServer((msg) => new Exception(msg)))), Substitute.For>(), new LocksServiceMock(), new DeviceMock(), new SpecialFolderMock(), null, // Cipher new PermissionsMock(), isConnectedFunc: () => false, 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 = MockRepository.GenerateStub(); var navigationService = MockRepository.GenerateStub(); var viewModel = new MapPageViewModel( tinkApp, new PermissionsMock(), NSubstitute.Substitute.For(), NSubstitute.Substitute.For(), (mapspan) => { }, viewService, navigationService); try { await viewModel.OnAppearing(); // Is called when page shows. Assert.AreEqual( "Simulated error thrown at GetStationsAsync.", viewModel.Exception.Message); // Verify pins on map Assert.AreEqual(8, viewModel.Pins.Count); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "4").Icon.Id.Contains("Green"), "Station 4 must be marked green because there is are bike."); Assert.IsTrue( viewModel.Pins.FirstOrDefault(pin => pin.Tag.ToString() == "31").Icon.Id.Contains("Red"), "Station 31 must be marked red because there is no bike."); // Verify buttons Assert.IsTrue(viewModel.IsToggleVisible, "TINK and Konrad are activated in settings."); Assert.AreEqual(Color.Blue , viewModel.TinkColor, "TINK bikes are hidden."); Assert.AreEqual(Color.Gray, viewModel.KonradColor, "Konrad bikes are shown."); Assert.AreEqual("Connection interrupted.", viewModel.StatusInfoText); } finally { await viewModel.OnDisappearing(); } } } }