mirror of
https://dev.azure.com/TeilRad/sharee.bike%20App/_git/Code
synced 2025-05-17 06:26:33 +02:00
Version 3.0.375
This commit is contained in:
parent
2c790239cb
commit
ca080c87c0
194 changed files with 10092 additions and 10464 deletions
|
@ -58,7 +58,7 @@ namespace TestShareeLib.Model.Bike.BluetoothLock
|
|||
new Guid(),
|
||||
"17"),
|
||||
"My Station Name").ToString(),
|
||||
Is.EqualTo("Id=MyBikeId;type=Cargo;state=Disposable"));
|
||||
Is.EqualTo("Id=MyBikeId;type=Cargo;state=Disposable;Lock id=42"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
|
|
@ -3,6 +3,7 @@ using NUnit.Framework;
|
|||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.BatteryNS;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS.EngineNS;
|
||||
using DriveType = TINK.Model.Bikes.BikeInfoNS.DriveNS.DriveType;
|
||||
|
||||
namespace TestShareeLib.Model.BikeInfo.DriveNS
|
||||
{
|
||||
|
|
|
@ -314,6 +314,252 @@ namespace TestShareeLib.Model.Connector
|
|||
}
|
||||
}";
|
||||
|
||||
private const string BIKESAVAILABLE2 = @"{
|
||||
""lang"" : ""de"",
|
||||
""user_group"" : [
|
||||
""FR300103"",
|
||||
""FR300101""
|
||||
],
|
||||
""uri_primary"" : ""https://shareeapp-primary.copri.eu"",
|
||||
""bikes_occupied"" : {
|
||||
""160317"" : {
|
||||
""station"" : ""FR101"",
|
||||
""bike_type"" : {
|
||||
""category"" : ""cargo"",
|
||||
""wheels"" : ""2""
|
||||
},
|
||||
""rental_minute_all"" : 2666,
|
||||
""description"" : ""Lastenrad Oliver Pieper"",
|
||||
""unit_price"" : ""2.00"",
|
||||
""end_time"" : ""2023-10-29 12:03:28"",
|
||||
""total_price"" : ""0.00"",
|
||||
""K_u"" : ""[72, 41, 3, -121, -121, -40, -125, -92, -70, -78, -12, -73, 11, -31, 108, 63, -22, 28, -73, 35, 0, 0, 0, 0]"",
|
||||
""real_clock"" : ""1 day 20:26"",
|
||||
""rentalog"" : """",
|
||||
""bike"" : ""FR1011"",
|
||||
""gps"" : {
|
||||
""latitude"" : ""47.9765599546954"",
|
||||
""longitude"" : ""7.82557798549533""
|
||||
},
|
||||
""request_time"" : ""2023-10-27 15:37:16.296418+02"",
|
||||
""aa_ride"" : ""0"",
|
||||
""state"" : ""occupied"",
|
||||
""lock_state"" : ""unlocked"",
|
||||
""K_seed"" : ""[-77, 79, -81, -34, 107, -34, -100, -29, 124, 30, -50, -63, -111, 0, 22, -19]"",
|
||||
""Ilockit_ID"" : ""ISHAREIT-2200536"",
|
||||
""system"" : ""Ilockit"",
|
||||
""computed_hours"" : ""44.1"",
|
||||
""freed_time"" : ""- 00:20"",
|
||||
""bike_group"" : [
|
||||
""FR300101""
|
||||
],
|
||||
""start_time"" : ""2023-10-27 15:37:24.371987+02"",
|
||||
""rental_description"" : {
|
||||
""tarif_elements"" : {
|
||||
""4"" : [
|
||||
""Max. Gebühr"",
|
||||
""24,00 € / 24 Std""
|
||||
],
|
||||
""1"" : [
|
||||
""Mietgebühr"",
|
||||
""2,00 € / 30 Min ""
|
||||
],
|
||||
""7"" : [
|
||||
""Aktuelle Mietzeit"",
|
||||
""1 Tag 20 Std 26 Min ""
|
||||
],
|
||||
""2"" : [
|
||||
""ab 2. Tag"",
|
||||
""3,00 € / 30 Min ""
|
||||
],
|
||||
""6"" : [
|
||||
""Gratis Mietzeit"",
|
||||
""20 Min / Tag""
|
||||
]
|
||||
},
|
||||
""reserve_timerange"" : ""15"",
|
||||
""name"" : ""E-Lastenrad private"",
|
||||
""id"" : ""5533""
|
||||
},
|
||||
""discount"" : ""-100%"",
|
||||
""uri_operator"" : ""https://shareeapp-fr01.copri.eu""
|
||||
}
|
||||
},
|
||||
""bike_info_html"" : ""site/bike_info_sharee_230922.html"",
|
||||
""agb_checked"" : ""1"",
|
||||
""user_tour"" : [],
|
||||
""last_used_operator"" : {
|
||||
""operator_name"" : ""TeilRad GmbH"",
|
||||
""operator_phone"" : ""+49 761 45370097"",
|
||||
""operator_email"" : ""hotline@sharee.bike"",
|
||||
""operator_hours"" : ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr""
|
||||
},
|
||||
""user_id"" : ""ohauff@posteo.de"",
|
||||
""impress_html"" : ""site/impress_1.html"",
|
||||
""authcookie"" : ""5781_f172cf59108fe53e7524c841847fee69_shoo0faiNg"",
|
||||
""faq_app_fullurl"" : ""https://sharee.bike/faq/fahrrad-nutzung"",
|
||||
""tariff_info_html"" : ""site/tarif_info_sharee_230922.html"",
|
||||
""agb_html"" : ""site/agb_sharee_2.html"",
|
||||
""response"" : ""bikes_available"",
|
||||
""bikes"" : {
|
||||
""FR1545"" : {
|
||||
""Ilockit_GUID"" : ""00000000-0000-0000-0000-e38bf9d32234"",
|
||||
""description"" : ""C2-02-00545"",
|
||||
""lock_state"" : ""locked"",
|
||||
""system"" : ""Ilockit"",
|
||||
""Ilockit_ID"" : ""ISHAREIT-2200545"",
|
||||
""state"" : ""available"",
|
||||
""aa_ride"" : ""0"",
|
||||
""smartlock_type"" : {
|
||||
""battery"" : {
|
||||
""charge_current_percent"" : ""100""
|
||||
},
|
||||
""engine"" : {
|
||||
""manufacturer"" : ""Ilockit""
|
||||
}
|
||||
},
|
||||
""bike_type"" : {
|
||||
""battery"" : {
|
||||
""charge_max_bars"" : ""5"",
|
||||
""charge_current_bars"" : ""0"",
|
||||
""charge_current_percent"" : ""0"",
|
||||
""hidden"" : ""0"",
|
||||
""backend_accessible"" : ""0""
|
||||
},
|
||||
""engine"" : {
|
||||
""manufacturer"" : ""dummy""
|
||||
},
|
||||
""category"" : ""cargo"",
|
||||
""wheels"" : ""2""
|
||||
},
|
||||
""station"" : ""FR101"",
|
||||
""uri_operator"" : ""https://shareeapp-fr01.copri.eu"",
|
||||
""gps"" : {
|
||||
""latitude"" : ""47.9767844"",
|
||||
""longitude"" : ""7.8258182""
|
||||
},
|
||||
""bike"" : ""FR1545"",
|
||||
""bike_group"" : [
|
||||
""FR300101""
|
||||
],
|
||||
""authed"" : ""1"",
|
||||
""rental_description"" : {
|
||||
""id"" : ""5533"",
|
||||
""reserve_timerange"" : ""15"",
|
||||
""name"" : ""E-Lastenrad private"",
|
||||
""tarif_type"" : ""3"",
|
||||
""tarif_elements"" : {
|
||||
""6"" : [
|
||||
""Gratis Mietzeit"",
|
||||
""20 Min / Tag""
|
||||
],
|
||||
""2"" : [
|
||||
""ab 2. Tag"",
|
||||
""3,00 € / 30 Min ""
|
||||
],
|
||||
""4"" : [
|
||||
""Max. Gebühr"",
|
||||
""24,00 € / 24 Std""
|
||||
],
|
||||
""1"" : [
|
||||
""Mietgebühr"",
|
||||
""2,00 € / 30 Min ""
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
""FR1012"" : {
|
||||
""uri_operator"" : ""https://shareeapp-fr01.copri.eu"",
|
||||
""bike"" : ""FR1012"",
|
||||
""gps"" : {
|
||||
""latitude"" : ""47.998034725897"",
|
||||
""longitude"" : ""7.78498157858849""
|
||||
},
|
||||
""bike_group"" : [
|
||||
""FR300101""
|
||||
],
|
||||
""rental_description"" : {
|
||||
""rental_info"" : {
|
||||
""1"" : [
|
||||
""Tracking"",
|
||||
""Ich stimme der Speicherung (Tracking) meiner Fahrstrecke zwecks wissenschaftlicher Auswertung und Berechnung der CO2-Einsparung zu!""
|
||||
]
|
||||
},
|
||||
""tarif_elements"" : {
|
||||
""1"" : [
|
||||
""Mietgebühr"",
|
||||
""2,00 € / 30 Min ""
|
||||
],
|
||||
""4"" : [
|
||||
""Max. Gebühr"",
|
||||
""24,00 € / 24 Std""
|
||||
],
|
||||
""6"" : [
|
||||
""Gratis Mietzeit"",
|
||||
""20 Min / Tag""
|
||||
],
|
||||
""2"" : [
|
||||
""ab 2. Tag"",
|
||||
""3,00 € / 30 Min ""
|
||||
]
|
||||
},
|
||||
""reserve_timerange"" : ""15"",
|
||||
""name"" : ""E-Lastenrad private"",
|
||||
""id"" : ""5533"",
|
||||
""tarif_type"" : ""3""
|
||||
},
|
||||
""authed"" : ""1"",
|
||||
""description"" : ""Contributor-bike devel"",
|
||||
""Ilockit_GUID"" : ""00000000-0000-0000-0000-ef6655036de7"",
|
||||
""lock_state"" : ""locked"",
|
||||
""system"" : ""Ilockit"",
|
||||
""Ilockit_ID"" : ""ISHAREIT-2309492"",
|
||||
""state"" : ""available"",
|
||||
""bike_type"" : {
|
||||
""engine"" : {
|
||||
""manufacturer"" : ""dummy""
|
||||
},
|
||||
""battery"" : {
|
||||
""charge_current_bars"" : ""5"",
|
||||
""charge_max_bars"" : ""5"",
|
||||
""backend_accessible"" : ""0"",
|
||||
""charge_current_percent"" : ""100"",
|
||||
""hidden"" : ""0""
|
||||
},
|
||||
""category"" : ""cargo"",
|
||||
""wheels"" : ""2""
|
||||
},
|
||||
""smartlock_type"" : {
|
||||
""engine"" : {
|
||||
""manufacturer"" : ""Ilockit""
|
||||
},
|
||||
""battery"" : {
|
||||
""charge_current_percent"" : """"
|
||||
}
|
||||
},
|
||||
""aa_ride"" : ""0"",
|
||||
""station"" : ""FR103""
|
||||
},
|
||||
},
|
||||
""aowner"" : ""186"",
|
||||
""init_map"" : {
|
||||
""radius"" : ""2.9"",
|
||||
""center"" : {
|
||||
""longitude"" : ""7.825490"",
|
||||
""latitude"" : ""47.976634""
|
||||
}
|
||||
},
|
||||
""new_authcoo"" : ""0"",
|
||||
""apiserver"" : ""https://shareeapp-fr01.copri.eu"",
|
||||
""merchant_id"" : ""shoo0faiNg"",
|
||||
""privacy_html"" : ""site/privacy_sharee_2.html"",
|
||||
""response_state"" : ""OK, nothing todo"",
|
||||
""debuglevel"" : ""104"",
|
||||
""clearing_cache"" : ""0"",
|
||||
""copri_version"" : ""4.1.23.20"",
|
||||
""project_id"" : ""Freiburg""
|
||||
}";
|
||||
|
||||
private const string BIKESAVAILABLEEMPTY = @"{
|
||||
""copri_version"" : ""4.1.0.0"",
|
||||
""bikes"" : {},
|
||||
|
@ -609,5 +855,46 @@ namespace TestShareeLib.Model.Connector
|
|||
Assert.IsNull(result.Exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestGetBikesOperratorUri()
|
||||
{
|
||||
var server = Substitute.For<ICachedCopriServer>();
|
||||
|
||||
server.GetBikesAvailable(operatorUri: Arg.Any<Uri>()).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
|
||||
typeof(CopriCallsHttps),
|
||||
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE2),
|
||||
new GeneralData())));
|
||||
|
||||
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync(new Uri("https://shareeapp-fr01.copri.eu//APIjsonserver"));
|
||||
|
||||
await server.DidNotReceive().GetBikesOccupied();
|
||||
await server.DidNotReceive().GetBikesOccupied(Arg.Any<bool>());
|
||||
server.Received().AddToCache(Arg.Any<Result<BikesAvailableResponse>>(), Arg.Any<Uri>());
|
||||
|
||||
Assert.AreEqual(3, result.Response.Count);
|
||||
Assert.AreEqual(typeof(CopriCallsHttps), result.Source);
|
||||
Assert.IsNull(result.Exception);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task TestGetBikesOperratorUriCache()
|
||||
{
|
||||
var server = Substitute.For<ICachedCopriServer>();
|
||||
|
||||
server.GetBikesAvailable(operatorUri: Arg.Any<Uri>()).Returns(Task.Run(() => new Result<BikesAvailableResponse>(
|
||||
typeof(CopriCallsMonkeyStore),
|
||||
JsonConvert.DeserializeObject<BikesAvailableResponse>(BIKESAVAILABLE2),
|
||||
new GeneralData())));
|
||||
|
||||
var result = await new CachedQueryLoggedIn(server, "123", "a@b", () => DateTime.Now).GetBikesAsync(new Uri("https://shareeapp-fr01.copri.eu//APIjsonserver"));
|
||||
|
||||
await server.DidNotReceive().GetBikesOccupied();
|
||||
await server.DidNotReceive().GetBikesOccupied(Arg.Any<bool>());
|
||||
server.DidNotReceive().AddToCache(Arg.Any<Result<BikesAvailableResponse>>(), Arg.Any<Uri>());
|
||||
|
||||
Assert.AreEqual(3, result.Response.Count);
|
||||
Assert.AreEqual(typeof(CopriCallsMonkeyStore), result.Source);
|
||||
Assert.IsNull(result.Exception);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,6 @@ using TINK.Model.Bikes.BikeInfoNS.BikeNS;
|
|||
using TINK.Model.Connector;
|
||||
using TINK.Repository.Exception;
|
||||
using TINK.Repository.Response;
|
||||
using TINK.Repository.Response.Stations;
|
||||
using TINK.Repository.Response.Stations.Station;
|
||||
using JsonConvertRethrow = TINK.Repository.Response.JsonConvertRethrow;
|
||||
|
||||
|
@ -1080,5 +1079,93 @@ namespace TestTINKLib.Fixtures.Connector
|
|||
}").GetMaxReservationTimeSpan().TotalMinutes,
|
||||
Is.EqualTo(15));
|
||||
|
||||
[Test]
|
||||
public void TestGetOperatorUriNull()
|
||||
=> Assert.That(
|
||||
TextToTypeHelper.GetOperatorUri(stationInfo: null),
|
||||
Is.Null);
|
||||
|
||||
[Test]
|
||||
public void TestGetOperatorUriEmpty()
|
||||
=> Assert.That(
|
||||
JsonConvertRethrow.DeserializeObject<StationInfo>(@"").GetOperatorUri(),
|
||||
Is.Null);
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestGetOperatorUriNoUri()
|
||||
=> Assert.That(
|
||||
JsonConvertRethrow.DeserializeObject<StationInfo>(@"
|
||||
{
|
||||
""station"": ""FR101""
|
||||
}").GetOperatorUri(),
|
||||
Is.Null);
|
||||
|
||||
[Test]
|
||||
public void TestGetOperatorUriInvalidUrl()
|
||||
=> Assert.That(
|
||||
JsonConvertRethrow.DeserializeObject<StationInfo>(@"
|
||||
{
|
||||
""station"": ""FR101"",
|
||||
""uri_operator"": ""ThisIsNoUrl""
|
||||
}").GetOperatorUri(),
|
||||
Is.Null);
|
||||
|
||||
[Test]
|
||||
public void TestGetOperatorUri()
|
||||
=> Assert.That(
|
||||
JsonConvertRethrow.DeserializeObject<StationInfo>(@"
|
||||
{
|
||||
""station"": ""FR101"",
|
||||
""uri_operator"": ""https://shareedms-tr.copri.eu""
|
||||
}").GetOperatorUri().AbsoluteUri,
|
||||
Is.EqualTo("https://shareedms-tr.copri.eu//APIjsonserver"));
|
||||
|
||||
|
||||
[Test]
|
||||
public void TestGetStation()
|
||||
{
|
||||
var stationInfo = JsonConvertRethrow.DeserializeObject<StationInfo>(@"{
|
||||
""station"": ""FR104"",
|
||||
""withpub"": ""1"",
|
||||
""cached"": ""1"",
|
||||
""authed"": ""1"",
|
||||
""state"": ""available"",
|
||||
""operator_data"": {
|
||||
""operator_email"": ""hotline@sharee.bike"",
|
||||
""operator_hours"": ""Bürozeiten: Montag, Mittwoch, Freitag 9-12 Uhr"",
|
||||
""operator_phone"": ""+49 761 45370097"",
|
||||
""operator_name"": ""TeilRad GmbH""
|
||||
},
|
||||
""station_type"": {
|
||||
""city"": {
|
||||
""bike_group"": ""FR300103"",
|
||||
""bike_count"": ""0""
|
||||
},
|
||||
""cargo"": {
|
||||
""bike_group"": ""FR300101"",
|
||||
""bike_count"": ""0""
|
||||
}
|
||||
},
|
||||
""uri_operator"": ""https://shareeapp-fr01.copri.eu"",
|
||||
""gps_radius"": ""50"",
|
||||
""capacity"": ""1"",
|
||||
""description"": ""fahrradspezialitäten"",
|
||||
""gps"": {
|
||||
""longitude"": ""7.837621"",
|
||||
""latitude"": ""47.989807""
|
||||
},
|
||||
""station_group"": [
|
||||
""FR300101"",
|
||||
""FR300103""
|
||||
],
|
||||
""bike_count"": ""0""
|
||||
}");
|
||||
|
||||
var station = stationInfo.GetStation();
|
||||
Assert.That(
|
||||
station.OperatorUri.AbsoluteUri,
|
||||
Is.EqualTo("https://shareeapp-fr01.copri.eu//APIjsonserver"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using TINK.Model.Bikes.BikeInfoNS.DriveNS;
|
||||
using TINK.Model.Connector.Updater;
|
||||
using TINK.Repository.Response;
|
||||
using DriveType = TINK.Model.Bikes.BikeInfoNS.DriveNS.DriveType;
|
||||
|
||||
namespace TestShareeLib.Model.Connector.Updater
|
||||
{
|
||||
|
|
|
@ -164,7 +164,7 @@ namespace TestShareeLib.Repository.Request
|
|||
|
||||
/// <summary> Hypothetical scenario.</summary>
|
||||
[Test]
|
||||
public void TestDoBookActionClose()
|
||||
public void TestDoBookActionCloseLock()
|
||||
{
|
||||
Assert.AreEqual(
|
||||
"request=booking_update&bike=42&authcookie=456123&Ilockit_GUID=0000f00d-1212-efde-1523-785fef13d123&state=occupied&lock_state=locking",
|
||||
|
|
32
TestShareeLib/TestShareeBikeLibCore.csproj
Normal file
32
TestShareeLib/TestShareeBikeLibCore.csproj
Normal file
|
@ -0,0 +1,32 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Compile Remove="Model\Bikes\BikeInfoNS\BC\TestBikeSerializeJSON.cs" />
|
||||
<Compile Remove="Model\Bikes\BikeInfoNS\TestBikeCollectionSerializeJSON.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<None Include="Model\Bikes\BikeInfoNS\BC\TestBikeSerializeJSON.cs" />
|
||||
<None Include="Model\Bikes\BikeInfoNS\TestBikeCollectionSerializeJSON.cs" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="NSubstitute" Version="5.1.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.7.2" />
|
||||
<PackageReference Include="Xamarin.Essentials" Version="1.8.0" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\TestFramework\TestFrameworkCore.csproj" />
|
||||
<ProjectReference Include="..\TINKLib\ShareeBikeLibCore.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -315,7 +315,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
|
@ -833,6 +832,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -894,6 +897,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Lock reports it is still closed. Please try again!", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -954,6 +961,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Position of lock bolt is unknown. Lock could be closed or open. Make sure that no spoke presses against the lock bolt and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -1019,6 +1030,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
"Please try again.",
|
||||
"OK"
|
||||
);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
|
|
@ -161,6 +161,10 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -221,6 +225,10 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -281,6 +289,10 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Lock reports it is still closed. Please try again!", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -341,6 +353,10 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
locks.Received()[0].OpenAsync(); // Lock must be closed
|
||||
bikesViewModel.ActionText = "";
|
||||
viewService.DisplayAlert("Lock could not be opened!", "Position of lock bolt is unknown. Lock could be closed or open. Make sure that no spoke presses against the lock bolt and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -405,6 +421,10 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
"Exception message.",
|
||||
"Please try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
|
|
@ -43,7 +43,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify prerequisites.
|
||||
Assert.AreEqual("Reserve bike", handler.ButtonText);
|
||||
Assert.IsTrue(handler.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", handler.LockitButtonText);
|
||||
Assert.IsFalse(handler.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
|
@ -95,16 +94,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve bike.
|
||||
/// Final state: Reserved closed.
|
||||
/// Final state: Booked open.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveAndConnect()
|
||||
public void TestReserveAndConnectAndOpen()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
|
@ -159,7 +157,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Searching lock...";
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
|
||||
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
|
||||
|
@ -181,6 +178,183 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve bike, book and open.
|
||||
/// Final state: Booked unspecific.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveAndConnectAndOpenOpenFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
var timeOuts = Substitute.For<ITimeOutProvider>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableDisconnected(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Reserve bike Nr. 0 free of charge for 15 min?", "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
|
||||
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build())); // Return lock state indicating success
|
||||
|
||||
locks.TimeOut.Returns(timeOuts);
|
||||
|
||||
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].OpenAsync()
|
||||
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Searching lock...";
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
|
||||
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
|
||||
locks.Received()[0].OpenAsync(); // Lock must be opened
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Lock could not be opened!",
|
||||
"Please try again.",
|
||||
"Exception message.",
|
||||
"OK"
|
||||
);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state "booked unspecific" after action
|
||||
Assert.AreEqual("BookedDisconnected", subsequent.ButtonText);
|
||||
Assert.IsFalse(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve bike, book and open.
|
||||
/// Final state: Booked unspecific.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestReserveAndConnectAndOpenOpenFailsCouldntOpenBoltBlockedException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
var timeOuts = Substitute.For<ITimeOutProvider>();
|
||||
|
||||
bike.TariffDescription.MaxReservationTimeSpan.Returns(TimeSpan.FromMinutes(15));
|
||||
|
||||
var handler = new DisposableDisconnected(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Reserve bike Nr. 0 free of charge for 15 min?", "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>())
|
||||
.Returns(Task.FromResult(new LockInfoTdo.Builder { State = LockitLockingState.Closed }.Build())); // Return lock state indicating success
|
||||
|
||||
locks.TimeOut.Returns(timeOuts);
|
||||
|
||||
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].OpenAsync()
|
||||
.Returns<Task<LockitLockingState?>>(x => throw new CouldntOpenBoldIsBlockedException());
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike); // Booking must be performed
|
||||
bikesViewModel.ActionText = "Searching lock...";
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
|
||||
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
|
||||
locks.Received()[0].OpenAsync(); // Lock must be opened
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Lock could not be opened!",
|
||||
"Lock bolt is blocked. Make sure that no spoke presses against the lock bolt and try again.",
|
||||
"OK"
|
||||
);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state "booked unspecific" after action
|
||||
Assert.AreEqual("Open lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Reserve bike.
|
||||
/// Final state: Same as initial state.
|
||||
|
@ -242,7 +416,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
|
@ -307,7 +480,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
|
@ -377,7 +549,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
|
@ -603,7 +774,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,198 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.AreEqual("Close lock or rent bike", handler.ButtonText);
|
||||
Assert.AreEqual("Rent bike", handler.ButtonText);
|
||||
Assert.IsTrue(handler.IsButtonVisible);
|
||||
Assert.AreEqual(nameof(DisposableOpen), handler.LockitButtonText);
|
||||
Assert.IsFalse(handler.IsLockitButtonVisible);
|
||||
Assert.AreEqual("Close lock", handler.LockitButtonText);
|
||||
Assert.IsTrue(handler.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Booked Open.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBook()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike);
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Close lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
|
||||
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Disposable Closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBookDoReserveFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
connector.Command.DoReserve(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Rent bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Disposable Closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBookDoReserveFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
connector.Command.DoReserve(bike).Returns(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reserving bike...";
|
||||
connector.Command.DoReserve(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert("Bike could not be reserved!", "Exception message.","Please try again.", "OK");
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Rent bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Close lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -79,13 +267,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
|
||||
|
||||
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -95,6 +282,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
|
@ -141,16 +332,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
|
||||
|
||||
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -162,6 +349,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be closed!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -206,16 +399,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(false));
|
||||
|
||||
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -232,6 +421,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
"Please try again.",
|
||||
"OK"
|
||||
);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -244,209 +439,5 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
Assert.AreEqual(nameof(DisposableDisconnected), subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Booked Open.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBook()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked);
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Close lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual(string.Empty, subsequent.LockitButtonText);
|
||||
Assert.That(subsequent.IsLockitButtonVisible, Is.False);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Disposable Closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBookDoBookFailsWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.DoBookAsync(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("chub")));
|
||||
|
||||
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Bike could not be rented!",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Disposable Closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDoBookDoBookFailsException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new DisposableOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Rent bike", "Close lock").Returns(Task.FromResult(true));
|
||||
|
||||
connector.Command.DoBookAsync(bike).Returns(x => throw new Exception("Exception message."));
|
||||
|
||||
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Bike could not be rented!", "Exception message.", "OK");
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Reserve bike", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("DisposableDisconnected", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -737,7 +737,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
viewService.DisplayAlert(string.Empty, string.Format("Rent bike {0} and open lock?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].OpenAsync()
|
||||
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message.")); // Return lock state indicating success
|
||||
.Returns<Task<LockitLockingState?>>(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Booking call leads to setting of state to booked.
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownFromHardwareError);
|
||||
|
|
|
@ -421,7 +421,6 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
connector.Command.CalculateAuthKeys(bike);
|
||||
bikesViewModel.ActionText = "Searching lock...";
|
||||
locks.ConnectAsync(Arg.Any<LockInfoAuthTdo>(), Arg.Any<TimeSpan>());
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open); // Booking must be performed
|
||||
bikesViewModel.ActionText = "<h4><b>Lock is opening.<br/>Please wait until it is completely open.</b></h4>";
|
||||
|
|
|
@ -43,10 +43,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
Substitute.For<IUser>());
|
||||
|
||||
// Verify prerequisites.
|
||||
Assert.AreEqual("Close lock or rent bike", handler.ButtonText);
|
||||
Assert.AreEqual("Close lock", handler.ButtonText);
|
||||
Assert.IsTrue(handler.IsButtonVisible);
|
||||
Assert.AreEqual("Alarm/ Sounds verwalten", handler.LockitButtonText);
|
||||
Assert.IsFalse(handler.IsLockitButtonVisible);
|
||||
Assert.AreEqual("Rent bike", handler.LockitButtonText);
|
||||
Assert.IsTrue(handler.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -78,12 +78,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Booked); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // Requesthandler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -91,11 +89,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
|
@ -137,15 +137,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
|
||||
|
||||
connector.Command.DoBookAsync(bike).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open).Returns(x => throw new WebConnectFailureException("Context info.", new Exception("Tst")));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // Requesthandler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -153,17 +150,17 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Bike could not be rented!",
|
||||
"Connection to booking system not possible.",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -171,15 +168,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
|
||||
Assert.AreEqual("Close lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
|
||||
Assert.AreEqual("Rent bike", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: User books bike.
|
||||
/// Final state: Reserved closed.
|
||||
/// Final state: Reserved open.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestBookBookFailsException()
|
||||
|
@ -206,15 +203,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(false));
|
||||
|
||||
connector.Command.DoBookAsync(bike).Returns(x => throw new Exception("Exception message."));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open).Returns(x => throw new Exception("Exception message."));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open); // Requesthandler factory queries lock state to create appropriate request handler object.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
var subsequent = handler.HandleRequestOption2().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
|
@ -222,18 +217,18 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Renting bike...";
|
||||
connector.Command.DoBookAsync(bike);
|
||||
connector.Command.DoBookAsync(bike, LockingAction.Open);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Bike could not be rented!",
|
||||
"Exception message.",
|
||||
"Please try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -241,15 +236,15 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
|
||||
Assert.AreEqual("Close lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Open lock & rent bike", subsequent.LockitButtonText);
|
||||
Assert.AreEqual("Rent bike", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Final state: Booked.
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Disposable Disconnected.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservation()
|
||||
|
@ -278,11 +273,12 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
locks[0].CloseAsync().Returns(Task.FromResult((LockitLockingState?)LockitLockingState.Closed));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(true));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
|
@ -294,8 +290,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Disconnecting lock...";
|
||||
locks.DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
|
@ -312,82 +310,11 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Final state: Reserved open.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservationCloseFailsOutOfReachException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].CloseAsync()
|
||||
.Returns<Task<LockitLockingState?>>(x => { throw new OutOfReachException(); });
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Lock could not be closed!",
|
||||
"Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.",
|
||||
"OK");
|
||||
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservationCloseFailsException()
|
||||
public void TestCloseLockCloseFailsOutOfReachExcption()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
|
@ -413,11 +340,76 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(
|
||||
string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new OutOfReachException());
|
||||
|
||||
locks[0].CloseAsync()
|
||||
.Returns<Task<LockitLockingState?>>(x => { throw new Exception("Exception message."); });
|
||||
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(false));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.UnknownDisconnected);
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert("Lock could not be closed!", "Make sure you have granted Bluetooth permission to the app. Step as close as possible to the bike lock and try again.", "OK");
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Lock bike.
|
||||
/// Final state: Same as initial state.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockCloseFailsCouldntCloseMovingException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
locks[0].CloseAsync().Returns<Task<LockitLockingState?>>(x => throw new CouldntCloseMovingException());
|
||||
|
||||
viewService.DisplayAlert(string.Empty, string.Format("Cancel reservation for bike {0}?", "Nr. 0"), "Yes", "No").Returns(Task.FromResult(false));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Reserved); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
bike.LockInfo.State.Returns(LockingState.Open);
|
||||
|
@ -437,8 +429,13 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Lock could not be closed!",
|
||||
"Step close to the lock and try again or report bike to operator!\r\nException message.",
|
||||
"OK");
|
||||
"The process is motion sensitive. Step close to the lock, do not move, and try again.",
|
||||
"OK"
|
||||
);
|
||||
bikesViewModel.ActionText = "Reading charging level...";
|
||||
locks[0].GetBatteryPercentageAsync();
|
||||
bikesViewModel.ActionText = "Updating lock state...";
|
||||
connector.Command.UpdateLockingStateAsync(bike, null);
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
|
@ -446,233 +443,10 @@ namespace TestTINKLib.Fixtures.ObjectTests.ViewModel.Bikes.Bike.BluetoothLock.Re
|
|||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("Cancel reservation", subsequent.ButtonText);
|
||||
Assert.AreEqual("Close lock", subsequent.ButtonText);
|
||||
Assert.IsTrue(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("Search lock", subsequent.LockitButtonText);
|
||||
Assert.AreEqual("Rent bike", subsequent.LockitButtonText);
|
||||
Assert.IsTrue(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Final state: Reserved closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservationCancelReservationInvalidAuthorizationResponseException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
var response = JsonConvert.DeserializeObject<AuthorizationResponse>(@"
|
||||
{
|
||||
""response"" : ""authorization"",
|
||||
""authcookie"" : ""4da3044c8657a04ba60e2eaa753bc51a"",
|
||||
""user_group"" : [ ""TINK"", ""Konrad"" ],
|
||||
""response_state"" : ""OK"",
|
||||
""apiserver"" : ""https://tinkwwp.copri-bike.de""
|
||||
}");
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new InvalidAuthorizationResponseException("mustermann@server.de", response));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"Your session has expired. Please login new and try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("InvalidState", subsequent.ButtonText);
|
||||
Assert.IsFalse(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Final state: Reserved closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservationCancelReservationWebConnectFailureException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new WebConnectFailureException("Context info", new Exception("chub")));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"A stable Internet connection is required. Connect to WIFI or to mobile network and activate mobile data. Try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("InvalidState", subsequent.ButtonText);
|
||||
Assert.IsFalse(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Use case: Close lock and cancel reservation.
|
||||
/// Final state: Reserved closed.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestCloseLockAndCancelReservationCancelReservationException()
|
||||
{
|
||||
var bike = Substitute.For<IBikeInfoMutable>();
|
||||
var connector = Substitute.For<IConnector>();
|
||||
var command = Substitute.For<ICommand>();
|
||||
var geolocation = Substitute.For<IGeolocationService>();
|
||||
var locks = Substitute.For<ILocksService>();
|
||||
var pollingManager = Substitute.For<IPollingUpdateTaskManager>();
|
||||
var viewService = Substitute.For<IViewService>();
|
||||
var bikesViewModel = Substitute.For<IBikesViewModel>();
|
||||
var activeUser = Substitute.For<IUser>();
|
||||
|
||||
var handler = new ReservedOpen(
|
||||
bike,
|
||||
() => true, // isConnectedDelegate
|
||||
(isConnexted) => connector,
|
||||
geolocation,
|
||||
locks,
|
||||
() => pollingManager,
|
||||
Substitute.For<ISmartDevice>(),
|
||||
viewService,
|
||||
bikesViewModel,
|
||||
activeUser);
|
||||
|
||||
bike.Id.Returns("0");
|
||||
|
||||
viewService.DisplayAlert(string.Empty, "Close lock or rent bike Nr. 0?", "Close lock", "Rent bike").Returns(Task.FromResult(true));
|
||||
|
||||
locks[0].CloseAsync().Returns(LockitLockingState.Closed);
|
||||
|
||||
connector.Command.DoCancelReservation(bike).Returns(x => throw new Exception("Exception message.", new Exception("chub")));
|
||||
|
||||
bike.State.Value.Returns(InUseStateEnum.Disposable); // Requesthandler factory queries state to create appropriate request handler object.
|
||||
|
||||
var subsequent = handler.HandleRequestOption1().Result;
|
||||
|
||||
locks.DidNotReceive().DisconnectAsync(Arg.Any<int>(), Arg.Any<Guid>());
|
||||
|
||||
// Verify behavior
|
||||
Received.InOrder(() =>
|
||||
{
|
||||
bikesViewModel.Received(1).IsIdle = false; // GUI must be locked
|
||||
bikesViewModel.ActionText = "One moment please...";
|
||||
pollingManager.StopAsync(); // Polling must be stopped before any COPR and lock service action
|
||||
bikesViewModel.ActionText = "The lock bolt moves through the spokes of the rear wheel.";
|
||||
locks[0].CloseAsync();
|
||||
bikesViewModel.ActionText = "Canceling reservation...";
|
||||
connector.Command.DoCancelReservation(bike);
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
viewService.DisplayAdvancedAlert(
|
||||
"Reservation could not be canceled!",
|
||||
"Exception message.",
|
||||
"Please try again.",
|
||||
"OK");
|
||||
bikesViewModel.ActionText = "Updating...";
|
||||
pollingManager.StartAsync(); // polling must be restarted again
|
||||
bikesViewModel.ActionText = string.Empty;
|
||||
bikesViewModel.Received(1).IsIdle = true; // GUI must be unlocked
|
||||
});
|
||||
|
||||
// Verify state after action
|
||||
Assert.AreEqual("InvalidState", subsequent.ButtonText);
|
||||
Assert.IsFalse(subsequent.IsButtonVisible);
|
||||
Assert.AreEqual("InvalidState", subsequent.LockitButtonText);
|
||||
Assert.IsFalse(subsequent.IsLockitButtonVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ namespace TestShareeLib.ViewModel.Bikes.Bike.BluetoothLock.RequestHandler
|
|||
|
||||
// Verify prerequisites.
|
||||
Assert.AreEqual("Open lock & rent bike", handler.ButtonText);
|
||||
Assert.IsFalse(handler.IsButtonVisible);
|
||||
Assert.IsTrue(handler.IsButtonVisible);
|
||||
Assert.AreEqual("Close lock", handler.LockitButtonText);
|
||||
Assert.IsTrue(handler.IsLockitButtonVisible);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue