From 8aa3089f320784da40b6c260b4ed67a59789e557 Mon Sep 17 00:00:00 2001 From: Oliver Hauff Date: Mon, 8 Nov 2021 23:11:56 +0100 Subject: [PATCH] Tests fixed. --- .../TINK/HtmlResouces/V02/InfoLicenses.html | 2 +- .../TINK/HtmlResouces/V02/InfoLicenses.html | 2 +- TINK/TINK/HtmlResouces/V02/InfoLicenses.html | 2 +- TINKLib/Model/Connector/Command/Command.cs | 22 +- .../Connector/FilteredConnectorFactory.cs | 5 +- .../Model/Connector/Updater/UpdaterJSON.cs | 16 +- TINKLib/Model/TinkApp.cs | 2 +- .../Model/User/Account/AccountExtensions.cs | 8 +- TINKLib/Model/User/Account/AccountMutable.cs | 4 - TINKLib/Model/User/User.cs | 43 +- TINKLib/Repository/CopriCallsMemory.cs | 2 +- TestShareeLib/Model/TestTinkApp.cs | 37 +- TestShareeLib/Model/TestTinkAppLogin.cs | 30 +- .../Repository/CopriCallMemoryBase.cs | 283 ++++++++++++ .../Repository/CopriCallsMemory001.cs | 403 ++++++++++++++++++ 15 files changed, 779 insertions(+), 82 deletions(-) create mode 100644 TestShareeLib/Repository/CopriCallMemoryBase.cs create mode 100644 TestShareeLib/Repository/CopriCallsMemory001.cs diff --git a/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html b/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html index e56447e..6c5e7aa 100644 --- a/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html +++ b/LastenradBayern/TINK/HtmlResouces/V02/InfoLicenses.html @@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken

diff --git a/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html b/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html index e56447e..6c5e7aa 100644 --- a/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html +++ b/Meinkonrad/TINK/HtmlResouces/V02/InfoLicenses.html @@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken

diff --git a/TINK/TINK/HtmlResouces/V02/InfoLicenses.html b/TINK/TINK/HtmlResouces/V02/InfoLicenses.html index e56447e..6c5e7aa 100644 --- a/TINK/TINK/HtmlResouces/V02/InfoLicenses.html +++ b/TINK/TINK/HtmlResouces/V02/InfoLicenses.html @@ -23,7 +23,7 @@
Version ACTIVE_APPNAME: CURRENT_VERSION_TINKAPP.
Entwickler
-
Programmierung ACTIVE_APPNAME: O. Hauff, o.hauff@sharee.bike.
+
Programmierung ACTIVE_APPNAME: O. Hauff, app@sharee.bike
Verwendete Bibliotheken

diff --git a/TINKLib/Model/Connector/Command/Command.cs b/TINKLib/Model/Connector/Command/Command.cs index 0dfe245..b839df7 100644 --- a/TINKLib/Model/Connector/Command/Command.cs +++ b/TINKLib/Model/Connector/Command/Command.cs @@ -36,36 +36,36 @@ namespace TINK.Model.Connector /// If communication fails an exception is thrown. /// public async Task DoLogin( - string p_strMail, - string p_strPassword, - string p_strDeviceId) + string mail, + string password, + string deviceId) { - if (string.IsNullOrEmpty(p_strMail)) + if (string.IsNullOrEmpty(mail)) { throw new ArgumentNullException("Can not loging user. Mail address must not be null or empty."); } - if (string.IsNullOrEmpty(p_strPassword)) + if (string.IsNullOrEmpty(password)) { throw new ArgumentNullException("Can not loging user. Password must not be null or empty."); } - if (string.IsNullOrEmpty(p_strDeviceId)) + if (string.IsNullOrEmpty(deviceId)) { throw new ArgumentNullException("Can not loging user. Device not be null or empty."); } - AuthorizationResponse l_oResponse; + AuthorizationResponse response; try { - l_oResponse = (await CopriServer.DoAuthorizationAsync(p_strMail, p_strPassword, p_strDeviceId)).GetIsResponseOk(p_strMail); + response = (await CopriServer.DoAuthorizationAsync(mail, password, deviceId)).GetIsResponseOk(mail); } catch (System.Exception) { throw; } - var l_oAccount = l_oResponse.GetAccount(MerchantId, p_strMail, p_strPassword); + var l_oAccount = response.GetAccount(MerchantId, mail, password); // Log in state changes. Notify parent object to update. LoginStateChanged?.Invoke(this, new LoginStateChangedEventArgs(l_oAccount.SessionCookie, l_oAccount.Mail)); @@ -83,9 +83,9 @@ namespace TINK.Model.Connector /// /// Request to reserve a bike. /// - /// Bike to book. + /// Bike to book. public async Task DoReserve( - Bikes.Bike.BC.IBikeInfoMutable p_oBike) + Bikes.Bike.BC.IBikeInfoMutable bike) { Log.ForContext().Error("Unexpected booking request detected. No user logged in."); await Task.CompletedTask; diff --git a/TINKLib/Model/Connector/FilteredConnectorFactory.cs b/TINKLib/Model/Connector/FilteredConnectorFactory.cs index 8005f01..5121035 100644 --- a/TINKLib/Model/Connector/FilteredConnectorFactory.cs +++ b/TINKLib/Model/Connector/FilteredConnectorFactory.cs @@ -5,12 +5,13 @@ namespace TINK.Model.Connector public static class FilteredConnectorFactory { /// Creates a filter object. - /// + /// Filter to apply on stations and bikes. + /// Connector to connect to COPRI. public static IFilteredConnector Create(IEnumerable group, IConnector connector) { return group != null ? (IFilteredConnector) new FilteredConnector(group, connector) - : new NullFilterConnector(connector); + : new NullFilterConnector(connector); // Do not apply filtering. } } } diff --git a/TINKLib/Model/Connector/Updater/UpdaterJSON.cs b/TINKLib/Model/Connector/Updater/UpdaterJSON.cs index ebae8d7..007895c 100644 --- a/TINKLib/Model/Connector/Updater/UpdaterJSON.cs +++ b/TINKLib/Model/Connector/Updater/UpdaterJSON.cs @@ -91,7 +91,7 @@ namespace TINK.Model.Connector { if (loginResponse == null) { - throw new ArgumentNullException("p_oLoginResponse"); + throw new ArgumentNullException(nameof(loginResponse)); } return new Account( @@ -165,13 +165,13 @@ namespace TINK.Model.Connector } /// Gets bikes available from copri server response. - /// Response to create collection from. + /// Response to create collection from. /// New collection of available bikes. public static BikeCollection GetBikesAvailable( - this BikesAvailableResponse p_oBikesAvailableResponse) + this BikesAvailableResponse bikesAvailableResponse) { return GetBikesAll( - p_oBikesAvailableResponse, + bikesAvailableResponse, new BikesReservedOccupiedResponse(), // There are no occupied bikes. string.Empty, () => DateTime.Now); @@ -198,8 +198,8 @@ namespace TINK.Model.Connector public static BikeCollection GetBikesAll( BikesAvailableResponse bikesAvailableResponse, BikesReservedOccupiedResponse bikesOccupiedResponse, - string p_strMail, - Func p_oDateTimeProvider) + string mail, + Func dateTimeProvider) { var bikesDictionary = new Dictionary(); var duplicates = new Dictionary(); @@ -242,8 +242,8 @@ namespace TINK.Model.Connector { BikeInfo bikeInfo = BikeInfoFactory.Create( bikeInfoResponse, - p_strMail, - p_oDateTimeProvider); + mail, + dateTimeProvider); if (bikeInfo == null) { diff --git a/TINKLib/Model/TinkApp.cs b/TINKLib/Model/TinkApp.cs index c69ea6c..4f56b24 100644 --- a/TINKLib/Model/TinkApp.cs +++ b/TINKLib/Model/TinkApp.cs @@ -147,7 +147,7 @@ namespace TINK.Model public TinkApp( Settings.Settings settings, IStore accountStore, - Func connectorFactory, + Func connectorFactory, IServicesContainer geolocationServicesContainer, ILocksService locksService, ISmartDevice device, diff --git a/TINKLib/Model/User/Account/AccountExtensions.cs b/TINKLib/Model/User/Account/AccountExtensions.cs index 6920435..5adac6e 100644 --- a/TINKLib/Model/User/Account/AccountExtensions.cs +++ b/TINKLib/Model/User/Account/AccountExtensions.cs @@ -6,12 +6,12 @@ namespace TINK.Model.User.Account public static class AccountExtensions { /// Gets information whether user is logged in or not from account object. - /// Object to get information from. + /// Object to get information from. /// True if user is logged in, false if not. - public static bool GetIsLoggedIn(this IAccount p_oAccount) + public static bool GetIsLoggedIn(this IAccount account) { - return !string.IsNullOrEmpty(p_oAccount.Mail) - && !string.IsNullOrEmpty(p_oAccount.SessionCookie); + return !string.IsNullOrEmpty(account.Mail) + && !string.IsNullOrEmpty(account.SessionCookie); } /// diff --git a/TINKLib/Model/User/Account/AccountMutable.cs b/TINKLib/Model/User/Account/AccountMutable.cs index 3323eea..d90947a 100644 --- a/TINKLib/Model/User/Account/AccountMutable.cs +++ b/TINKLib/Model/User/Account/AccountMutable.cs @@ -12,10 +12,6 @@ namespace TINK.Model.User.Account /// private Account m_oAccount; - /// Prevents an invalid instance to be created. - private AccountMutable() - { - } public AccountMutable(IAccount p_oSource) { diff --git a/TINKLib/Model/User/User.cs b/TINKLib/Model/User/User.cs index 6d1b079..fe82673 100644 --- a/TINKLib/Model/User/User.cs +++ b/TINKLib/Model/User/User.cs @@ -13,15 +13,13 @@ namespace TINK.Model.User /// public class User : IUser { - /// - /// Holds account data. - /// - private readonly AccountMutable m_oAccount; + /// Holds account data. + private AccountMutable Account { get; } /// /// Provides storing functionality. /// - private IStore m_oStore; + private IStore Store { get; } /// Holds the id of the device. public string DeviceId { get; } @@ -34,10 +32,10 @@ namespace TINK.Model.User IAccount account, string deviceId) { - m_oStore = accountStore + Store = accountStore ?? throw new ArgumentException("Can not instantiate user- object. No store functionality available."); DeviceId = deviceId; - m_oAccount = new AccountMutable(account); + Account = new AccountMutable(account); } /// Is fired wheneverlogin state changes. @@ -46,19 +44,14 @@ namespace TINK.Model.User /// /// Holds a value indicating whether user is logged in or not. /// - public bool IsLoggedIn { - get - { - return m_oAccount.GetIsLoggedIn(); - } - } + public bool IsLoggedIn => Account.GetIsLoggedIn(); /// /// Holds the mail address. /// public string Mail { - get { return m_oAccount.Mail; } + get { return Account.Mail; } } /// @@ -66,24 +59,24 @@ namespace TINK.Model.User /// public string SessionCookie { - get { return m_oAccount.SessionCookie; } + get { return Account.SessionCookie; } } /// /// Holds the password. /// public string Password { - get { return m_oAccount.Pwd; } + get { return Account.Pwd; } } /// Holds the debug level. public Permissions DebugLevel { - get { return m_oAccount.DebugLevel; } + get { return Account.DebugLevel; } } /// Holds the group of the bike (TINK, Konrad, ...). - public IEnumerable Group { get { return m_oAccount.Group; } } + public IEnumerable Group { get { return Account.Group; } } /// Logs in user. /// Account to use for login. @@ -93,7 +86,7 @@ namespace TINK.Model.User { if (IsLoggedIn) { - throw new Exception($"Can not log in user {mail} because user {m_oAccount} is already logged in."); + throw new Exception($"Can not log in user {mail} because user {Account} is already logged in."); } // Check if password might be valid before connecting to copri. @@ -113,10 +106,10 @@ namespace TINK.Model.User public async Task Login(IAccount account) { // Update account instance from copri data. - m_oAccount.Copy(account); + Account.Copy(account); // Save data to store. - await m_oStore.Save(m_oAccount); + await Store.Save(Account); // Nothing to do because state did not change. StateChanged?.Invoke(this, new EventArgs()); @@ -128,7 +121,7 @@ namespace TINK.Model.User { var l_oPreviousState = IsLoggedIn; - m_oAccount.Copy(m_oStore.Delete(m_oAccount)); + Account.Copy(Store.Delete(Account)); if (IsLoggedIn == l_oPreviousState) { @@ -144,11 +137,11 @@ namespace TINK.Model.User /// Some user may be "TINK"- user only, some "Konrad" and some may be "TINK" and "Konrad" users. /// /// Account to filter with. - /// Groups to filter.. + /// Groups to filter.. /// Filtered bike groups. - public IEnumerable DoFilter(IEnumerable p_oSource = null) + public IEnumerable DoFilter(IEnumerable source = null) { - return m_oAccount.DoFilter(p_oSource); + return Account.DoFilter(source); } } } diff --git a/TINKLib/Repository/CopriCallsMemory.cs b/TINKLib/Repository/CopriCallsMemory.cs index 629ab20..9fbb72a 100644 --- a/TINKLib/Repository/CopriCallsMemory.cs +++ b/TINKLib/Repository/CopriCallsMemory.cs @@ -1264,7 +1264,7 @@ namespace TINK.Repository } }"; - private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2; + private const SampleSets DEFAULT_SAMPLE_SET = SampleSets.Set2; private const int DEFAULT_STAGE_INDEX = 1; diff --git a/TestShareeLib/Model/TestTinkApp.cs b/TestShareeLib/Model/TestTinkApp.cs index 7d1b8bf..10240d4 100644 --- a/TestShareeLib/Model/TestTinkApp.cs +++ b/TestShareeLib/Model/TestTinkApp.cs @@ -2,9 +2,7 @@ using System; using TINK.Model; using TINK.Model.Connector; -using TINK.Repository; using TINK.Model.Services.CopriApi.ServerUris; -using static TINK.Repository.CopriCallsMemory; using TINK.Services; using NSubstitute; using TINK.Model.Services.Geolocation; @@ -12,8 +10,8 @@ using TINK.Services.BluetoothLock; using TINK.Model.Device; using TINK.Model.User.Account; using Plugin.Permissions.Abstractions; -using System.Threading.Tasks; -using System.Collections.Generic; + +using TestShareeLib.Repository; namespace TestTINKLib.Fixtures.UseCases.Logout { @@ -32,9 +30,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout accountStore.Load().Returns(account); account.Mail.Returns("javaminister@gmail.com"); - account.Pwd.Returns("javaminister"); - account.SessionCookie.Returns("4da3044c8657a04ba60e2eaa753bc51a"); - account.Group.Returns(new List { "TINK" }); + account.Pwd.Returns("*********"); + account.SessionCookie.Returns("6103_112e96b36ba33de245943c5ffaf369cd_"); // No user logged in is initial state to verify. var l_oTinkApp = new TinkApp( @@ -44,8 +41,8 @@ namespace TestTINKLib.Fixtures.UseCases.Logout activeUri: new Uri(CopriServerUriList.TINK_DEVEL)), accountStore, (isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie) - ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1)) - : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), + ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001()) + : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), Substitute.For>(), locksService, device, @@ -57,17 +54,29 @@ namespace TestTINKLib.Fixtures.UseCases.Logout lastVersion: new Version(3, 0, 173)); // Current app version. Must be larger or equal 3.0.173 to Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn); - Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count); - Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count); - Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie); + // There are 6 bikes available and 2, one reserved and one rented by javaminsiter. + Assert.AreEqual( + 8, + l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count, + "Sum of bikes is 6 occupied plus 2 occupied."); + Assert.AreEqual(2, + l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count, + "Javaminster occupies 2 bikes."); + Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie); // Log user out. l_oTinkApp.GetConnector(true).Command.DoLogout().Wait(); l_oTinkApp.ActiveUser.Logout(); Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn); - Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count); - Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count); + Assert.AreEqual( + 6, + l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count, + "Sum of bikes is 6 occupied, no one occupied because no user is logged in"); + Assert.AreEqual( + 0, + l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count, + "If no user is logged in no occupied bikes are shown."); Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie); } } diff --git a/TestShareeLib/Model/TestTinkAppLogin.cs b/TestShareeLib/Model/TestTinkAppLogin.cs index 5c35e43..ccb1638 100644 --- a/TestShareeLib/Model/TestTinkAppLogin.cs +++ b/TestShareeLib/Model/TestTinkAppLogin.cs @@ -13,10 +13,10 @@ using TINK.Model.Device; using TINK.Model.User.Account; using Plugin.Permissions.Abstractions; using System.Threading.Tasks; +using TestShareeLib.Repository; namespace TestTINKLib.Fixtures.UseCases.Login { - [TestFixture] public class TestTinkApp { @@ -37,8 +37,8 @@ namespace TestTINKLib.Fixtures.UseCases.Login activeUri: new Uri(CopriServerUriList.TINK_DEVEL)), accountStore, (isConnected, uri, sessionCookie, mail, expiresAfter) => string.IsNullOrEmpty(sessionCookie) - ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1)) as IConnector - : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory(SampleSets.Set2, 1, sessionCookie)), + ? new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001()) as IConnector + : new ConnectorCache(sessionCookie, mail, new CopriCallsMemory001(sessionCookie)), Substitute.For>(), locksService, device, @@ -50,18 +50,30 @@ namespace TestTINKLib.Fixtures.UseCases.Login lastVersion: new Version(3, 0, 173) /* Current app version. Must be larger or equal 3.0.173 to lastVersion*/); Assert.IsFalse(l_oTinkApp.ActiveUser.IsLoggedIn); - Assert.AreEqual(11, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count); - Assert.AreEqual(0, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count); + Assert.AreEqual( + 6, + l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count, + "Sum of bikes is 6 occupied, no one occupied because no user is logged in"); + Assert.AreEqual( + 0, + l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count, + "If no user is logged in no occupied bikes are shown."); Assert.IsNull(l_oTinkApp.GetConnector(true).Command.SessionCookie); // Log user out. - var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "javaminister", "HwId1000000000000").Result; + var l_oAccount = l_oTinkApp.GetConnector(true).Command.DoLogin("javaminister@gmail.com", "*********", "HwId1000000000000").Result; await l_oTinkApp.ActiveUser.Login(l_oAccount); Assert.IsTrue(l_oTinkApp.ActiveUser.IsLoggedIn); - Assert.AreEqual(13, l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count); - Assert.AreEqual(2, l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count); - Assert.AreEqual("4da3044c8657a04ba60e2eaa753bc51a", l_oTinkApp.GetConnector(true).Command.SessionCookie); + Assert.AreEqual( + 8, + l_oTinkApp.GetConnector(true).Query.GetBikesAsync().Result.Response.Count, + "Sum of bikes is 6 occupied plus 2 occupied."); + Assert.AreEqual( + 2, + l_oTinkApp.GetConnector(true).Query.GetBikesOccupiedAsync().Result.Response.Count, + "Javaminster occupies 2 bikes."); + Assert.AreEqual("6103_112e96b36ba33de245943c5ffaf369cd_", l_oTinkApp.GetConnector(true).Command.SessionCookie); } } } diff --git a/TestShareeLib/Repository/CopriCallMemoryBase.cs b/TestShareeLib/Repository/CopriCallMemoryBase.cs new file mode 100644 index 0000000..c9e2aa9 --- /dev/null +++ b/TestShareeLib/Repository/CopriCallMemoryBase.cs @@ -0,0 +1,283 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using TINK.Model; +using TINK.Model.Device; +using TINK.Repository; +using TINK.Repository.Request; +using TINK.Repository.Response; + +namespace TestShareeLib.Repository +{ + /// Provides functionality for keeping a set of COPRI responses. + public abstract class CopriCallMemoryBase + { + private string BikesAvailableResponse { get; } + + private string BikesOccupiedResponse { get; } + + private string AuthResponse { get; } + + private string AuthOutResponse { get; } + + private string Stations { get; } + + private string BookingRequestResponse { get; } + + private string CancelBookingRequestResponse { get; } + + private IRequestBuilder requestBuilder; + + public CopriCallMemoryBase( + string bikesAvailableResponse = null, + string bikesOccupiedResponse = null, + string authResponse = null, + string authOutResponse = null, + string stations = null, + string bookingRequestResponse = null, + string cancelBookingRequestResponse = null, + string sessionCookie = null) + { + SessionCookie = sessionCookie; + + BikesAvailableResponse = bikesAvailableResponse; + BikesOccupiedResponse = bikesOccupiedResponse; + AuthResponse = authResponse; + AuthOutResponse = authOutResponse; + BookingRequestResponse = bookingRequestResponse; + CancelBookingRequestResponse = cancelBookingRequestResponse; + + Stations = stations; + + requestBuilder = string.IsNullOrEmpty(sessionCookie) + ? new RequestBuilder(MerchantId) as IRequestBuilder + : new RequestBuilderLoggedIn(MerchantId, sessionCookie); + + } + + /// Holds the session id of the logged in user, null otherwise. + public string SessionCookie { get; private set; } + + /// Logs user in. + /// User to log in. + /// Id specifying user and hardware. + /// Mailaddress of user to log in. + /// Password to log in. + /// Response which holds auth cookie + public async Task DoAuthorizationAsync( + string mailAddress, + string password, + string deviceId) + => await Task.Run(() => DoAuthorize(AuthResponse, mailAddress, password, deviceId)); + + /// Logs user out. + /// User to log in. + /// Response which holds auth cookie + public async Task DoAuthoutAsync() + => await Task.Run(() => DoAuthout(AuthOutResponse, SessionCookie)); + + /// + /// Gets list of bikes from memory. + /// + /// + public async Task GetBikesAvailableAsync() + => await Task.Run(() => GetBikesAvailable(BikesAvailableResponse, null, SessionCookie)); + + /// + /// Gets a list of bikes reserved/ booked by acctive user from Copri. + /// + /// Cookie to authenticate user. + /// Response holding list of bikes. + public async Task GetBikesOccupiedAsync() + { + try + { + requestBuilder.GetBikesOccupied(); // Non mock implementation if ICopriServer call this member as well. To ensure comparable behaviour this member is called here as well. + } + catch (NotSupportedException) + { + // No user logged in. + await Task.CompletedTask; + return ResponseHelper.GetBikesOccupiedNone(); + } + return await Task.Run(() => GetBikesOccupied(BikesOccupiedResponse, SessionCookie)); + } + + /// + /// Get list of stations from file. + /// + /// Auto cookie of user if user is logged in. + /// List of files. + public async Task GetStationsAsync() + => await Task.Run(() => GetStationsAll(Stations, null, SessionCookie)); + + /// + /// Gets booking request response. + /// + /// Id of the bike to book. + /// Booking response. + public async Task DoReserveAsync(string bikeId, Uri operatorUri) + => await Task.Run(() => DoReserve(BookingRequestResponse, bikeId, SessionCookie)); + + /// + /// Gets canel booking request response. + /// + /// Id of the bike to book. + /// Cookie of the logged in user. + /// Response on cancel booking request. + public async Task DoCancelReservationAsync(string bikeId, Uri operatorUri) + => await Task.Run(() => DoCancelReservation(CancelBookingRequestResponse, bikeId, SessionCookie)); + + + /// Gets the merchant id. + public string MerchantId => TinkApp.MerchantId; + + /// Returns false because cached values are returned. + public bool IsConnected => false; + + /// Logs user in. + /// User to log in. + /// Id specifying user and hardware. + /// Mailaddress of user to log in. + /// Password to log in. + /// Response which holds auth cookie + public static AuthorizationResponse DoAuthorize( + string DoAuthResponse, + string p_strMailAddress, + string p_strPassword, + string p_strDeviceId) + { + return p_strMailAddress == "javaminister@gmail.com" + && p_strPassword == "*********" && + p_strDeviceId == "HwId1000000000000" + ? JsonConvertRethrow.DeserializeObject>(DoAuthResponse).shareejson + : JsonConvertRethrow.DeserializeObject>(DO_AUTH_Unknown_User_FILE).shareejson; + + } + + /// Logs user in. + /// Response which holds auth cookie + public static AuthorizationoutResponse DoAuthout( + string authOutResponse, + string sessionCookie) + { + // Response contains auth cookie of user "JavaministerHardwareNr1" + // For this reason do not return answer if mail and pwd do not match. + + return !string.IsNullOrEmpty(sessionCookie) + ? JsonConvertRethrow.DeserializeObject>(authOutResponse).shareejson + : throw new NotSupportedException(); + + } + + /// + /// Gets list of bikes from memory. + /// + /// Id of the merchant. + /// Auto cookie of user if user is logged in. + /// Set of samples. + /// Index of the stage. + /// + public static BikesAvailableResponse GetBikesAvailable( + string BikesAvailableResponse, + string p_strMerchantId, + string p_strSessionCookie = null) => CopriCallsStatic.DeserializeResponse(BikesAvailableResponse); + + /// + /// Gets stations response. + /// + /// Id of the merchant. + /// Auto cookie of user if user is logged in. + /// + /// + /// + public static StationsAvailableResponse GetStationsAll( + string stations, + string merchantId, + string cookie = null) + => JsonConvertRethrow.DeserializeObject>(stations).shareejson; + + /// + /// Gets booking request response. + /// + /// Id of the bike. + /// Identifies the logged in user. + /// Sample set to use. + /// Index of the stage. + /// + public static ReservationBookingResponse DoReserve( + string bookingRequestResponse, + string bikeId, + string sessionCookie) + => JsonConvertRethrow.DeserializeObject>(bookingRequestResponse).shareejson; + + /// + /// Gets canel booking request response. + /// + /// Id of the bike to book. + /// Cookie of the logged in user. + /// Response on cancel booking request. + public static ReservationCancelReturnResponse DoCancelReservation( + string cancelBookingRequestResponse, + string bikeId, + string cookie) + => JsonConvertRethrow.DeserializeObject>(cancelBookingRequestResponse).shareejson; + + public Task CalculateAuthKeysAsync(string bikeId, Uri operatorUri) + => null; + + public Task UpdateLockingStateAsync( + string bikeId, + LocationDto geolocation, + lock_state state, + double batteryLevel, + Uri operatorUri) + => null; + + public Task DoBookAsync(string bikeId, Guid guid, double batteryPercentage, Uri operatorUri) + => null; + + public Task DoReturn( + string bikeId, + LocationDto geolocation, + ISmartDevice smartDevice, + Uri operatorUri) + => null; + + public Task DoSubmitFeedback(string bikeId, string message, bool isBikeBroken, Uri operatorUri) + => null; + + /// Submits mini survey to copri server. + /// Collection of answers. + public Task DoSubmitMiniSurvey(IDictionary answers) + => null; + + /// + /// Gets a list of bikes reserved/ booked by acctive user from Copri. + /// + /// Cookie to authenticate user. + /// Sample set to use. + /// Index of the stage. + /// Response holding list of bikes. + public static BikesReservedOccupiedResponse GetBikesOccupied( + string bikesOccupied, + string sessionCookie = null) + { + var response = CopriCallsStatic.DeserializeResponse(bikesOccupied); + return sessionCookie != null && (response?.authcookie?.Contains(sessionCookie) ?? false) + ? response + : ResponseHelper.GetBikesOccupiedNone(sessionCookie); + + } + + public const string DO_AUTH_Unknown_User_FILE = @" + { + ""shareejson"" : { + ""response"" : ""authorization"", + ""authcookie"" : 0, + ""response_state"" : ""Failure: cannot generate authcookie"", + ""apiserver"" : ""https://tinkwwp.copri-bike.de"" + } + }"; + } +} diff --git a/TestShareeLib/Repository/CopriCallsMemory001.cs b/TestShareeLib/Repository/CopriCallsMemory001.cs new file mode 100644 index 0000000..ebd7319 --- /dev/null +++ b/TestShareeLib/Repository/CopriCallsMemory001.cs @@ -0,0 +1,403 @@ +using TINK.Repository; + +namespace TestShareeLib.Repository +{ + /// + /// Holds some COPRI responses for testing purposes. + /// + /// Holds some demo Meinkonrad and LastenradBayern bikes + /// + public class CopriCallsMemory001 : CopriCallMemoryBase, ICopriServer + { + public CopriCallsMemory001(string sessionCookie = null) : base( + bikesAvailableResponse: BikesAvailableResponse, + bikesOccupiedResponse: BikesOccupiedResponse, + authResponse: AuthResponse, + authOutResponse: AuthOutResponse, + sessionCookie: sessionCookie) + { } + + private static string AuthResponse => @"{ + ""shareejson"": { + ""clearing_cache"": ""0"", + ""privacy_html"": ""site/privacy.html"", + ""user_id"": ""javaminister@gmail.com"", + ""impress_html"": ""site/impress.html"", + ""tariff_info_html"": ""site/tariff_info_1.html"", + ""lang"": ""DE"", + ""last_used_operator"": { + ""operator_name"": ""sharee.bike | TeilRad GmbH"", + ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"", + ""operator_phone"": ""+49 761 45370097"", + ""operator_email"": ""hotline@sharee.bike"", + ""operator_color"": ""#009699"" + }, + ""response"": ""authorization"", + ""agb_checked"": ""0"", + ""agb_html"": ""site/agb.html"", + ""response_text"": ""Herzlich willkommen im Fahrradmietsystem"", + ""bike_info_html"": ""site/bike_info.html"", + ""debuglevel"": ""1"", + ""uri_primary"": ""https://shareeapp-primary.copri.eu"", + ""response_state"": ""OK, nothing todo"", + ""new_authcoo"": ""1"", + ""user_tour"": [], + ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"", + ""copri_version"": ""4.1.8.21"", + ""apiserver"": ""https://shareeapp-fr01.copri.eu"", + ""user_group"": [] + } + }"; + + private static string AuthOutResponse = @"{ + ""shareejson"": { + ""copri_version"": ""4.1.8.21"", + ""authcookie"": ""1"", + ""user_tour"": [], + ""user_group"": null, + ""apiserver"": ""https://shareeapp-fr01.copri.eu"", + ""debuglevel"": ""1"", + ""uri_primary"": ""https://shareeapp-primary.copri.eu"", + ""bike_info_html"": ""site/bike_info.html"", + ""response_state"": ""OK, logout"", + ""new_authcoo"": ""0"", + ""lang"": ""DE"", + ""last_used_operator"": { + ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"", + ""operator_name"": ""sharee.bike | TeilRad GmbH"", + ""operator_email"": ""hotline@sharee.bike"", + ""operator_phone"": ""+49 761 45370097"", + ""operator_color"": ""#009699"" + }, + ""tariff_info_html"": ""site/tariff_info_1.html"", + ""impress_html"": ""site/impress.html"", + ""response_text"": ""Auf Wiedersehen."", + ""agb_html"": ""site/agb.html"", + ""response"": ""authout"", + ""agb_checked"": ""0"", + ""privacy_html"": ""site/privacy.html"", + ""clearing_cache"": ""0"", + ""user_id"": ""javaminister@gmail.com"" + } + }"; + + private static string BikesOccupiedResponse => @"{ + ""shareejson"": { + ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"", + ""copri_version"": ""4.1.8.21"", + ""user_tour"": [], + ""user_group"": [ + ""FR300103"", + ""FR300101"" + ], + ""bikes_occupied"": { + ""157056"": { + ""K_seed"": ""[-20, -104, -112, -49, 3, -74, -43, -115, -53, 34, -48, -29, -64, -90, -26, -74]"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""bike"": ""FR1544"", + ""unit_price"": ""3.00"", + ""description"": ""Contributor-Paul"", + ""station"": ""FR103"", + ""request_time"": ""2021-11-06 18:57:20.034438+01"", + ""Ilockit_ID"": ""ISHAREIT-2200544"", + ""total_price"": ""25.50"", + ""bike_group"": [ + ""FR300103"" + ], + ""K_u"": ""[43, -16, 72, -5, 23, -117, 43, 57, 124, -106, -115, 97, -93, -30, -34, -7, -21, 119, 109, 92, 0, 0, 0, 0]"", + ""computed_hours"": ""8.50"", + ""end_time"": ""2021-11-08 21:14:35"", + ""state"": ""occupied"", + ""tariff_description"": { + ""eur_per_hour"": ""3.00"", + ""number"": ""5494"", + ""max_eur_per_day"": ""10.00"", + ""name"": ""Tester Basic"", + ""free_hours"": ""0.50"", + ""track_info"": ""Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!"", + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""lock_state"": ""locked"", + ""system"": ""Ilockit"", + ""gps"": { + ""latitude"": ""47.9994661873206"", + ""longitude"": ""7.7904340904206"" + }, + ""real_hours"": ""50.2833333333333"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-dc969f648732"", + ""start_time"": ""2021-11-06 18:57:25.445447+01"" + }, + ""157072"": { + ""bike"": ""FR1004"", + ""K_seed"": ""[-31, -81, -41, 95, 112, -113, -78, -22, 84, -112, -73, 31, -125, -49, 125, 10]"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""bike_group"": [ + ""FR300103"" + ], + ""total_price"": ""0.00"", + ""description"": ""Contributor-Recumbent"", + ""station"": ""FR103"", + ""request_time"": ""2021-11-08 21:10:24.829395+01"", + ""Ilockit_ID"": ""ISHAREIT-2302373"", + ""unit_price"": ""3.00"", + ""end_time"": ""2021-11-08 21:10:00+01"", + ""state"": ""requested"", + ""tariff_description"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."", + ""free_hours"": ""0.50"", + ""name"": ""Tester Basic"", + ""max_eur_per_day"": ""10.00"", + ""eur_per_hour"": ""3.00"", + ""number"": ""5494"" + }, + ""computed_hours"": ""0"", + ""K_u"": ""[126, -125, 125, 83, 104, -121, -80, 40, 77, -35, 81, 27, 89, -124, -37, 57, 118, -113, 71, -37, 0, 0, 0, 0]"", + ""start_time"": ""2021-11-08 21:10:24.829395+01"", + ""gps"": { + ""latitude"": ""47.9980777"", + ""longitude"": ""7.7848769"" + }, + ""lock_state"": ""locked"", + ""system"": ""Ilockit"", + ""real_hours"": ""0"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-fe3962c08bcc"" + } + }, + ""apiserver"": ""https://shareeapp-fr01.copri.eu"", + ""uri_primary"": ""https://shareeapp-primary.copri.eu"", + ""debuglevel"": ""1"", + ""bike_info_html"": ""site/bike_info.html"", + ""new_authcoo"": ""0"", + ""response_state"": ""OK, nothing todo"", + ""last_used_operator"": { + ""operator_color"": ""#008dd2"", + ""operator_phone"": ""+49 089 / 111111111"", + ""operator_email"": ""hotline@lastenraddemo.bayern"", + ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"", + ""operator_name"": ""Lastenrad Bayern"", + ""operator_logo"": """" + }, + ""lang"": ""DE"", + ""impress_html"": ""site/impress.html"", + ""tariff_info_html"": ""site/tariff_info_1.html"", + ""agb_html"": ""site/agb.html"", + ""response"": ""user_bikes_occupied"", + ""agb_checked"": ""1"", + ""privacy_html"": ""site/privacy.html"", + ""clearing_cache"": ""0"", + ""user_id"": ""ohauff@posteo.de"" + } + }"; + + private static string BikesAvailableResponse => @"{ + ""shareejson"": { + ""agb_checked"": ""1"", + ""response"": ""bikes_available"", + ""agb_html"": ""site/agb.html"", + ""impress_html"": ""site/impress.html"", + ""tariff_info_html"": ""site/tariff_info_1.html"", + ""lang"": ""DE"", + ""last_used_operator"": { + ""operator_color"": ""#008dd2"", + ""operator_email"": ""hotline@lastenraddemo.bayern"", + ""operator_phone"": ""+49 089 / 111111111"", + ""operator_name"": ""Lastenrad Bayern"", + ""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"", + ""operator_logo"": """" + }, + ""user_id"": ""ohauff@posteo.de"", + ""clearing_cache"": ""0"", + ""privacy_html"": ""site/privacy.html"", + ""bikes"": { + ""FR1543"": { + ""system"": ""Ilockit"", + ""gps"": { + ""longitude"": ""7.8255321"", + ""latitude"": ""47.9767121"" + }, + ""lock_state"": ""locked"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-cc141a6f68bb"", + ""state"": ""available"", + ""tariff_description"": { + ""free_hours"": ""0.50"", + ""name"": ""Tester Basic"", + ""eur_per_hour"": ""3.00"", + ""number"": ""5494"", + ""1543"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""max_eur_per_day"": ""10.00"" + }, + ""bike_group"": [ + ""FR300103"" + ], + ""station"": ""FR101"", + ""description"": ""Contributor-bike Dominik"", + ""Ilockit_ID"": ""ISHAREIT-2200543"", + ""authed"": ""1"", + ""bike"": ""FR1543"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"" + }, + ""FR1003"": { + ""bike"": ""FR1003"", + ""authed"": ""1"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""bike_group"": [ + ""FR300101"" + ], + ""Ilockit_ID"": ""ISHAREIT-2200545"", + ""station"": ""FR101"", + ""description"": ""Stadtrad"", + ""tariff_description"": { + ""max_eur_per_day"": ""10.00"", + ""number"": ""5491"", + ""eur_per_hour"": ""2.00"", + ""1003"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""free_hours"": ""0.50"", + ""name"": ""Vauban Basic"" + }, + ""state"": ""available"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-e38bf9d32234"", + ""system"": ""Ilockit"", + ""gps"": { + ""longitude"": ""7.8255772"", + ""latitude"": ""47.9765188"" + }, + ""lock_state"": ""locked"" + }, + ""FR1540"": { + ""bike_group"": [ + ""FR300103"" + ], + ""Ilockit_ID"": ""ISHAREIT-2200540"", + ""description"": ""Contributor-bike Dieter"", + ""station"": ""FR101"", + ""bike"": ""FR1540"", + ""authed"": ""1"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-fc3c002a2add"", + ""system"": ""Ilockit"", + ""gps"": { + ""longitude"": ""7.8256267"", + ""latitude"": ""47.976803"" + }, + ""lock_state"": ""locked"", + ""tariff_description"": { + ""1540"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""free_hours"": ""0.50"", + ""name"": ""Tester Basic"", + ""max_eur_per_day"": ""10.00"", + ""eur_per_hour"": ""3.00"", + ""number"": ""5494"" + }, + ""state"": ""available"" + }, + ""FR1002"": { + ""bike_group"": [ + ""FR300101"" + ], + ""description"": ""Lasten-Dreirad"", + ""station"": ""FR101"", + ""Ilockit_ID"": ""ISHAREIT-2200539"", + ""authed"": ""1"", + ""bike"": ""FR1002"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""gps"": { + ""latitude"": ""47.976552"", + ""longitude"": ""7.8255068"" + }, + ""system"": ""Ilockit"", + ""lock_state"": ""locked"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-f0b4a692e169"", + ""state"": ""available"", + ""tariff_description"": { + ""max_eur_per_day"": ""10.00"", + ""1002"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""eur_per_hour"": ""2.00"", + ""number"": ""5491"", + ""free_hours"": ""0.50"", + ""name"": ""Vauban Basic"" + } + }, + ""FR1538"": { + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""authed"": ""1"", + ""bike"": ""FR1538"", + ""station"": ""FR105"", + ""description"": ""Contributor-bike Rainer"", + ""Ilockit_ID"": ""ISHAREIT-2200538"", + ""bike_group"": [ + ""FR300103"" + ], + ""state"": ""available"", + ""tariff_description"": { + ""max_eur_per_day"": ""10.00"", + ""eur_per_hour"": ""3.00"", + ""number"": ""5494"", + ""1538"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + }, + ""free_hours"": ""0.50"", + ""name"": ""Tester Basic"" + }, + ""gps"": { + ""latitude"": ""47.9275957"", + ""longitude"": ""7.973976"" + }, + ""lock_state"": ""locked"", + ""system"": ""Ilockit"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-db0319a2555b"" + }, + ""FR1001"": { + ""bike_group"": [ + ""FR300101"" + ], + ""station"": ""FR101"", + ""description"": ""Lastenrad"", + ""Ilockit_ID"": ""ISHAREIT-2200536"", + ""authed"": ""1"", + ""bike"": ""FR1001"", + ""uri_operator"": ""https://shareeapp-fr01.copri.eu"", + ""lock_state"": ""locked"", + ""gps"": { + ""latitude"": ""47.9765091"", + ""longitude"": ""7.8255631"" + }, + ""system"": ""Ilockit"", + ""Ilockit_GUID"": ""00000000-0000-0000-0000-caa87760e53e"", + ""state"": ""available"", + ""tariff_description"": { + ""free_hours"": ""0.50"", + ""name"": ""Vauban Basic"", + ""eur_per_hour"": ""2.00"", + ""number"": ""5491"", + ""max_eur_per_day"": ""10.00"", + ""1001"": { + ""operator_agb"": ""Mit der Mietrad Anmietung wird folgender Betreiber AGB zugestimmt (als Demo sharee AGB)."" + } + } + } + }, + ""user_group"": [ + ""FR300103"", + ""FR300101"" + ], + ""apiserver"": ""https://shareeapp-fr01.copri.eu"", + ""user_tour"": [], + ""authcookie"": ""6103_112e96b36ba33de245943c5ffaf369cd_oiF2kahH"", + ""copri_version"": ""4.1.8.21"", + ""response_state"": ""OK, nothing todo"", + ""new_authcoo"": ""0"", + ""bike_info_html"": ""site/bike_info.html"", + ""debuglevel"": ""1"", + ""uri_primary"": ""https://shareeapp-primary.copri.eu"" + } + }"; + } +}