From 3f9c8793f5aece1983b960672fffab46a1634d2b Mon Sep 17 00:00:00 2001 From: James Skimming Date: Sat, 6 Jan 2018 19:46:29 +0000 Subject: [PATCH 1/2] Added the charge state model --- src/Tesla.NET/Models/ChargeState.cs | 403 ++++++++++++ .../Models/ChargeStateTests.cs | 581 ++++++++++++++++++ .../Models/GetChargeStateResponse.json | 45 ++ test/Tesla.NET.Tests/Models/SampleJson.cs | 6 + test/Tesla.NET.Tests/Tesla.NET.Tests.csproj | 1 + 5 files changed, 1036 insertions(+) create mode 100644 src/Tesla.NET/Models/ChargeState.cs create mode 100644 test/Tesla.NET.Tests/Models/ChargeStateTests.cs create mode 100644 test/Tesla.NET.Tests/Models/GetChargeStateResponse.json diff --git a/src/Tesla.NET/Models/ChargeState.cs b/src/Tesla.NET/Models/ChargeState.cs new file mode 100644 index 0000000..e025158 --- /dev/null +++ b/src/Tesla.NET/Models/ChargeState.cs @@ -0,0 +1,403 @@ +// Copyright (c) 2018 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Tesla.NET.Models +{ + using System; + using System.Diagnostics; + using System.Globalization; + using Newtonsoft.Json; + + /// + /// The charge state of a . + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class ChargeState + { + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + /// The . + public ChargeState( + string chargingState = default, + string fastChargerType = default, + string fastChargerBrand = default, + long chargeLimitSoc = default, + long chargeLimitSocStd = default, + long chargeLimitSocMin = default, + long chargeLimitSocMax = default, + bool chargeToMaxRange = default, + long maxRangeChargeCounter = default, + bool fastChargerPresent = default, + double batteryRange = default, + double estBatteryRange = default, + double idealBatteryRange = default, + long batteryLevel = default, + long usableBatteryLevel = default, + double chargeEnergyAdded = default, + double chargeMilesAddedRated = default, + long chargeMilesAddedIdeal = default, + long chargerVoltage = default, + long chargerPilotCurrent = default, + long chargerActualCurrent = default, + long chargerPower = default, + long timeToFullCharge = default, + bool tripCharging = default, + long chargeRate = default, + bool chargePortDoorOpen = default, + string connChargeCable = default, + string scheduledChargingStartTime = default, + bool scheduledChargingPending = default, + string userChargeEnableRequest = default, + bool chargeEnableRequest = default, + int? chargerPhases = default, + string chargePortLatch = default, + long chargeCurrentRequest = default, + long chargeCurrentRequestMax = default, + bool managedChargingActive = default, + bool managedChargingUserCanceled = default, + string managedChargingStartTime = default, + bool batteryHeaterOn = default, + bool notEnoughPowerToHeat = default, + long timestamp = default) + { + ChargingState = chargingState ?? string.Empty; + FastChargerType = fastChargerType ?? string.Empty; + FastChargerBrand = fastChargerBrand ?? string.Empty; + ChargeLimitSoc = chargeLimitSoc; + ChargeLimitSocStd = chargeLimitSocStd; + ChargeLimitSocMin = chargeLimitSocMin; + ChargeLimitSocMax = chargeLimitSocMax; + ChargeToMaxRange = chargeToMaxRange; + MaxRangeChargeCounter = maxRangeChargeCounter; + FastChargerPresent = fastChargerPresent; + BatteryRange = batteryRange; + EstBatteryRange = estBatteryRange; + IdealBatteryRange = idealBatteryRange; + BatteryLevel = batteryLevel; + UsableBatteryLevel = usableBatteryLevel; + ChargeEnergyAdded = chargeEnergyAdded; + ChargeMilesAddedRated = chargeMilesAddedRated; + ChargeMilesAddedIdeal = chargeMilesAddedIdeal; + ChargerVoltage = chargerVoltage; + ChargerPilotCurrent = chargerPilotCurrent; + ChargerActualCurrent = chargerActualCurrent; + ChargerPower = chargerPower; + TimeToFullCharge = timeToFullCharge; + TripCharging = tripCharging; + ChargeRate = chargeRate; + ChargePortDoorOpen = chargePortDoorOpen; + ConnChargeCable = connChargeCable ?? string.Empty; + ScheduledChargingStartTime = scheduledChargingStartTime ?? string.Empty; + ScheduledChargingPending = scheduledChargingPending; + UserChargeEnableRequest = userChargeEnableRequest ?? string.Empty; + ChargeEnableRequest = chargeEnableRequest; + ChargerPhases = chargerPhases; + ChargePortLatch = chargePortLatch ?? string.Empty; + ChargeCurrentRequest = chargeCurrentRequest; + ChargeCurrentRequestMax = chargeCurrentRequestMax; + ManagedChargingActive = managedChargingActive; + ManagedChargingUserCanceled = managedChargingUserCanceled; + ManagedChargingStartTime = managedChargingStartTime ?? string.Empty; + BatteryHeaterOn = batteryHeaterOn; + NotEnoughPowerToHeat = notEnoughPowerToHeat; + Timestamp = timestamp; + } + + /// + /// Gets the charging state of a . + /// + [JsonProperty("charging_state")] + public string ChargingState { get; } + + /// + /// Gets the type of fast charging. + /// + [JsonProperty("fast_charger_type")] + public string FastChargerType { get; } + + /// + /// Gets the brand of fast charging. + /// + [JsonProperty("fast_charger_brand")] + public string FastChargerBrand { get; } + + /// + /// Gets the charge limit . + /// + [JsonProperty("charge_limit_soc")] + public long ChargeLimitSoc { get; } + + /// + /// Gets the standard charge limit of a . + /// + [JsonProperty("charge_limit_soc_std")] + public long ChargeLimitSocStd { get; } + + /// + /// Gets the minimum change limit of a . + /// + [JsonProperty("charge_limit_soc_min")] + public long ChargeLimitSocMin { get; } + + /// + /// Gets the maximum change limit of a . + /// + [JsonProperty("charge_limit_soc_max")] + public long ChargeLimitSocMax { get; } + + /// + /// Gets a value indicating whether a will change to max range. + /// + [JsonProperty("charge_to_max_range")] + public bool ChargeToMaxRange { get; } + + /// + /// Gets the counter of haw many times a has been changed to maximum range. + /// + [JsonProperty("max_range_charge_counter")] + public long MaxRangeChargeCounter { get; } + + /// + /// Gets a value indicating whether a is supercharging. + /// + [JsonProperty("fast_charger_present")] + public bool FastChargerPresent { get; } + + /// + /// Gets the batter range of a . + /// + [JsonProperty("battery_range")] + public double BatteryRange { get; } + + /// + /// Gets the estimated battery range of a . + /// + [JsonProperty("est_battery_range")] + public double EstBatteryRange { get; } + + /// + /// Gets the ideal battery range of a . + /// + [JsonProperty("ideal_battery_range")] + public double IdealBatteryRange { get; } + + /// + /// Gets the current battery level of a . + /// + [JsonProperty("battery_level")] + public long BatteryLevel { get; } + + /// + /// Gets the usable battery level of a . + /// + [JsonProperty("usable_battery_level")] + public long UsableBatteryLevel { get; } + + /// + /// Gets the energy added to a at the last charge. + /// + [JsonProperty("charge_energy_added")] + public double ChargeEnergyAdded { get; } + + /// + /// Gets the rated miles added to a at the last charge. + /// + [JsonProperty("charge_miles_added_rated")] + public double ChargeMilesAddedRated { get; } + + /// + /// Gets the ideal miles added to a at the last charge. + /// + [JsonProperty("charge_miles_added_ideal")] + public long ChargeMilesAddedIdeal { get; } + + /// + /// Gets the charge voltage of a when charging. + /// + [JsonProperty("charger_voltage")] + public long ChargerVoltage { get; } + + /// + /// Gets the charge pilot current of a when charging. + /// + [JsonProperty("charger_pilot_current")] + public long ChargerPilotCurrent { get; } + + /// + /// Gets the charge actual current of a when charging. + /// + [JsonProperty("charger_actual_current")] + public long ChargerActualCurrent { get; } + + /// + /// Gets the charge power of a when charging. + /// + [JsonProperty("charger_power")] + public long ChargerPower { get; } + + /// + /// Gets the time in minutes to a full charge of a when charging. + /// + [JsonProperty("time_to_full_charge")] + public long TimeToFullCharge { get; } + + /// + /// Gets a value indicating whether a is trip charging. + /// + [JsonProperty("trip_charging")] + public bool TripCharging { get; } + + /// + /// Gets the charge rate of a when charging. + /// + [JsonProperty("charge_rate")] + public long ChargeRate { get; } + + /// + /// Gets a value indicating whether the charge port of a is open. + /// + [JsonProperty("charge_port_door_open")] + public bool ChargePortDoorOpen { get; } + + /// + /// Gets the type of the charge cable connected to a . + /// + [JsonProperty("conn_charge_cable")] + public string ConnChargeCable { get; } + + /// + /// Gets the schedule charging start time of a . + /// + [JsonProperty("scheduled_charging_start_time")] + public string ScheduledChargingStartTime { get; } + + /// + /// Gets a value indicating whether scheduled charging is pending for a . + /// + [JsonProperty("scheduled_charging_pending")] + public bool ScheduledChargingPending { get; } + + /// + /// Gets a value indicating whether a user charge enable request has been made for a . + /// + [JsonProperty("user_charge_enable_request")] + public string UserChargeEnableRequest { get; } + + /// + /// Gets a value indicating whether a charge enable request has been made for a . + /// + [JsonProperty("charge_enable_request")] + public bool ChargeEnableRequest { get; } + + /// + /// Gets the charger phases of a . + /// + [JsonProperty("charger_phases")] + public int? ChargerPhases { get; } + + /// + /// Gets the charge port latch of a . + /// + [JsonProperty("charge_port_latch")] + public string ChargePortLatch { get; } + + /// + /// Gets the charge current request of a . + /// + [JsonProperty("charge_current_request")] + public long ChargeCurrentRequest { get; } + + /// + /// Gets the maximum charge current request of a . + /// + [JsonProperty("charge_current_request_max")] + public long ChargeCurrentRequestMax { get; } + + /// + /// Gets a value indicating whether managed charging is active for a . + /// + [JsonProperty("managed_charging_active")] + public bool ManagedChargingActive { get; } + + /// + /// Gets a value indicating whether managed charging for has been canceled by a user. + /// + [JsonProperty("managed_charging_user_canceled")] + public bool ManagedChargingUserCanceled { get; } + + /// + /// Gets the managed charging start time of a . + /// + [JsonProperty("managed_charging_start_time")] + public string ManagedChargingStartTime { get; } + + /// + /// Gets a value indicating whether battery heating is on for a . + /// + [JsonProperty("battery_heater_on")] + public bool BatteryHeaterOn { get; } + + /// + /// Gets a value indicating whether there is not enough power to heat a . + /// + [JsonProperty("not_enough_power_to_heat")] + public bool NotEnoughPowerToHeat { get; } + + /// + /// Gets the millisecond Epoch timestamp when the was captured. + /// + [JsonProperty("timestamp")] + public long Timestamp { get; } + + /// + /// Gets the UTC when the was captured. + /// + [JsonIgnore] + public DateTime TimestampUtc => EpochConversion.FromMilliseconds(Timestamp); + + private string DebuggerDisplay => + $"{GetType().Name}: {ChargingState} @ {BatteryLevel}% giving " + + $"{EstBatteryRange.ToString(CultureInfo.InvariantCulture)}"; + } +} diff --git a/test/Tesla.NET.Tests/Models/ChargeStateTests.cs b/test/Tesla.NET.Tests/Models/ChargeStateTests.cs new file mode 100644 index 0000000..6e99cca --- /dev/null +++ b/test/Tesla.NET.Tests/Models/ChargeStateTests.cs @@ -0,0 +1,581 @@ +// Copyright (c) 2018 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Tesla.NET.Models +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using AutoFixture; + using FluentAssertions; + using Newtonsoft.Json.Linq; + using Xunit; + using Xunit.Abstractions; + + public class When_serializing_ChargeState_Should_serialize : FixtureContext + { + private readonly ChargeState _sut; + private readonly JObject _json; + + public When_serializing_ChargeState_Should_serialize(ITestOutputHelper output) + : base(output) + { + _sut = Fixture.Create(); + _json = JObject.FromObject(_sut); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + _json); + } + + [Fact] + public void forty_one_properties() => _json.Count.Should().Be(41); + + [Fact] + public void charging_state() => + _json["charging_state"].Value().Should().Be(_sut.ChargingState); + + [Fact] + public void fast_charger_type() => + _json["fast_charger_type"].Value().Should().Be(_sut.FastChargerType); + + [Fact] + public void fast_charger_brand() => + _json["fast_charger_brand"].Value().Should().Be(_sut.FastChargerBrand); + + [Fact] + public void charge_limit_soc() => + _json["charge_limit_soc"].Value().Should().Be(_sut.ChargeLimitSoc); + + [Fact] + public void charge_limit_soc_std() => + _json["charge_limit_soc_std"].Value().Should().Be(_sut.ChargeLimitSocStd); + + [Fact] + public void charge_limit_soc_min() => + _json["charge_limit_soc_min"].Value().Should().Be(_sut.ChargeLimitSocMin); + + [Fact] + public void charge_limit_soc_max() => + _json["charge_limit_soc_max"].Value().Should().Be(_sut.ChargeLimitSocMax); + + [Fact] + public void charge_to_max_range() => + _json["charge_to_max_range"].Value().Should().Be(_sut.ChargeToMaxRange); + + [Fact] + public void max_range_charge_counter() => + _json["max_range_charge_counter"].Value().Should().Be(_sut.MaxRangeChargeCounter); + + [Fact] + public void fast_charger_present() => + _json["fast_charger_present"].Value().Should().Be(_sut.FastChargerPresent); + + [Fact] + public void battery_range() => + _json["battery_range"].Value().Should().Be(_sut.BatteryRange); + + [Fact] + public void est_battery_range() => + _json["est_battery_range"].Value().Should().Be(_sut.EstBatteryRange); + + [Fact] + public void ideal_battery_range() => + _json["ideal_battery_range"].Value().Should().Be(_sut.IdealBatteryRange); + + [Fact] + public void battery_level() => + _json["battery_level"].Value().Should().Be(_sut.BatteryLevel); + + [Fact] + public void usable_battery_level() => + _json["usable_battery_level"].Value().Should().Be(_sut.UsableBatteryLevel); + + [Fact] + public void charge_energy_added() => + _json["charge_energy_added"].Value().Should().Be(_sut.ChargeEnergyAdded); + + [Fact] + public void charge_miles_added_rated() => + _json["charge_miles_added_rated"].Value().Should().Be(_sut.ChargeMilesAddedRated); + + [Fact] + public void charge_miles_added_ideal() => + _json["charge_miles_added_ideal"].Value().Should().Be(_sut.ChargeMilesAddedIdeal); + + [Fact] + public void charger_voltage() => + _json["charger_voltage"].Value().Should().Be(_sut.ChargerVoltage); + + [Fact] + public void charger_pilot_current() => + _json["charger_pilot_current"].Value().Should().Be(_sut.ChargerPilotCurrent); + + [Fact] + public void charger_actual_current() => + _json["charger_actual_current"].Value().Should().Be(_sut.ChargerActualCurrent); + + [Fact] + public void charger_power() => + _json["charger_power"].Value().Should().Be(_sut.ChargerPower); + + [Fact] + public void time_to_full_charge() => + _json["time_to_full_charge"].Value().Should().Be(_sut.TimeToFullCharge); + + [Fact] + public void trip_charging() => + _json["trip_charging"].Value().Should().Be(_sut.TripCharging); + + [Fact] + public void charge_rate() => + _json["charge_rate"].Value().Should().Be(_sut.ChargeRate); + + [Fact] + public void charge_port_door_open() => + _json["charge_port_door_open"].Value().Should().Be(_sut.ChargePortDoorOpen); + + [Fact] + public void conn_charge_cable() => + _json["conn_charge_cable"].Value().Should().Be(_sut.ConnChargeCable); + + [Fact] + public void scheduled_charging_start_time() => + _json["scheduled_charging_start_time"].Value().Should().Be(_sut.ScheduledChargingStartTime); + + [Fact] + public void scheduled_charging_pending() => + _json["scheduled_charging_pending"].Value().Should().Be(_sut.ScheduledChargingPending); + + [Fact] + public void user_charge_enable_request() => + _json["user_charge_enable_request"].Value().Should().Be(_sut.UserChargeEnableRequest); + + [Fact] + public void charge_enable_request() => + _json["charge_enable_request"].Value().Should().Be(_sut.ChargeEnableRequest); + + [Fact] + public void charger_phases() => + _json["charger_phases"].Value().Should().Be(_sut.ChargerPhases); + + [Fact] + public void charge_port_latch() => + _json["charge_port_latch"].Value().Should().Be(_sut.ChargePortLatch); + + [Fact] + public void charge_current_request() => + _json["charge_current_request"].Value().Should().Be(_sut.ChargeCurrentRequest); + + [Fact] + public void charge_current_request_max() => + _json["charge_current_request_max"].Value().Should().Be(_sut.ChargeCurrentRequestMax); + + [Fact] + public void managed_charging_active() => + _json["managed_charging_active"].Value().Should().Be(_sut.ManagedChargingActive); + + [Fact] + public void managed_charging_user_canceled() => + _json["managed_charging_user_canceled"].Value().Should().Be(_sut.ManagedChargingUserCanceled); + + [Fact] + public void managed_charging_start_time() => + _json["managed_charging_start_time"].Value().Should().Be(_sut.ManagedChargingStartTime); + + [Fact] + public void battery_heater_on() => + _json["battery_heater_on"].Value().Should().Be(_sut.BatteryHeaterOn); + + [Fact] + public void not_enough_power_to_heat() => + _json["not_enough_power_to_heat"].Value().Should().Be(_sut.NotEnoughPowerToHeat); + + [Fact] + public void timestamp() => + _json["timestamp"].Value().Should().Be(_sut.Timestamp); + } + + public class When_serializing_and_deserializing_ChargeState : FixtureContext + { + private readonly ChargeState _expected; + private readonly ChargeState _actual; + + public When_serializing_and_deserializing_ChargeState(ITestOutputHelper output) + : base(output) + { + _expected = Fixture.Create(); + JObject json = JObject.FromObject(_expected); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + json); + + _actual = json.ToObject(); + } + + [Fact] + public void Should_retain_all_properties() => _actual.ShouldBeEquivalentTo(_expected, WithStrictOrdering); + } + + public class When_deserializing_ChargeState_Should_deserialize : FixtureContext + { + private readonly ChargeState _sut; + private readonly JObject _json; + + public When_deserializing_ChargeState_Should_deserialize(ITestOutputHelper output) + : base(output) + { + _json = SampleJson.ChargeState; + _sut = _json.ToObject(); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + _json); + } + + [Fact] + public void charging_state() => + _sut.ChargingState.Should().Be(_json["charging_state"].Value()); + + [Fact] + public void fast_charger_type() => + _sut.FastChargerType.Should().Be(_json["fast_charger_type"].Value()); + + [Fact] + public void fast_charger_brand() => + _sut.FastChargerBrand.Should().Be(_json["fast_charger_brand"].Value()); + + [Fact] + public void charge_limit_soc() => + _sut.ChargeLimitSoc.Should().Be(_json["charge_limit_soc"].Value()); + + [Fact] + public void charge_limit_soc_std() => + _sut.ChargeLimitSocStd.Should().Be(_json["charge_limit_soc_std"].Value()); + + [Fact] + public void charge_limit_soc_min() => + _sut.ChargeLimitSocMin.Should().Be(_json["charge_limit_soc_min"].Value()); + + [Fact] + public void charge_limit_soc_max() => + _sut.ChargeLimitSocMax.Should().Be(_json["charge_limit_soc_max"].Value()); + + [Fact] + public void charge_to_max_range() => + _sut.ChargeToMaxRange.Should().Be(_json["charge_to_max_range"].Value()); + + [Fact] + public void max_range_charge_counter() => + _sut.MaxRangeChargeCounter.Should().Be(_json["max_range_charge_counter"].Value()); + + [Fact] + public void fast_charger_present() => + _sut.FastChargerPresent.Should().Be(_json["fast_charger_present"].Value()); + + [Fact] + public void battery_range() => + _sut.BatteryRange.Should().Be(_json["battery_range"].Value()); + + [Fact] + public void est_battery_range() => + _sut.EstBatteryRange.Should().Be(_json["est_battery_range"].Value()); + + [Fact] + public void ideal_battery_range() => + _sut.IdealBatteryRange.Should().Be(_json["ideal_battery_range"].Value()); + + [Fact] + public void battery_level() => + _sut.BatteryLevel.Should().Be(_json["battery_level"].Value()); + + [Fact] + public void usable_battery_level() => + _sut.UsableBatteryLevel.Should().Be(_json["usable_battery_level"].Value()); + + [Fact] + public void charge_energy_added() => + _sut.ChargeEnergyAdded.Should().Be(_json["charge_energy_added"].Value()); + + [Fact] + public void charge_miles_added_rated() => + _sut.ChargeMilesAddedRated.Should().Be(_json["charge_miles_added_rated"].Value()); + + [Fact] + public void charge_miles_added_ideal() => + _sut.ChargeMilesAddedIdeal.Should().Be(_json["charge_miles_added_ideal"].Value()); + + [Fact] + public void charger_voltage() => + _sut.ChargerVoltage.Should().Be(_json["charger_voltage"].Value()); + + [Fact] + public void charger_pilot_current() => + _sut.ChargerPilotCurrent.Should().Be(_json["charger_pilot_current"].Value()); + + [Fact] + public void charger_actual_current() => + _sut.ChargerActualCurrent.Should().Be(_json["charger_actual_current"].Value()); + + [Fact] + public void charger_power() => + _sut.ChargerPower.Should().Be(_json["charger_power"].Value()); + + [Fact] + public void time_to_full_charge() => + _sut.TimeToFullCharge.Should().Be(_json["time_to_full_charge"].Value()); + + [Fact] + public void trip_charging() => + _sut.TripCharging.Should().Be(_json["trip_charging"].Value()); + + [Fact] + public void charge_rate() => + _sut.ChargeRate.Should().Be(_json["charge_rate"].Value()); + + [Fact] + public void charge_port_door_open() => + _sut.ChargePortDoorOpen.Should().Be(_json["charge_port_door_open"].Value()); + + [Fact] + public void conn_charge_cable() => + _sut.ConnChargeCable.Should().Be(_json["conn_charge_cable"].Value()); + + [Fact] + public void scheduled_charging_start_time() => + _sut.ScheduledChargingStartTime.Should().Be(_json["scheduled_charging_start_time"].Value()); + + [Fact] + public void scheduled_charging_pending() => + _sut.ScheduledChargingPending.Should().Be(_json["scheduled_charging_pending"].Value()); + + [Fact] + public void user_charge_enable_request() => + _sut.UserChargeEnableRequest.Should().Be(_json["user_charge_enable_request"].Value()); + + [Fact] + public void charge_enable_request() => + _sut.ChargeEnableRequest.Should().Be(_json["charge_enable_request"].Value()); + + [Fact] + public void charger_phases() => + _sut.ChargerPhases.Should().Be(_json["charger_phases"].Value()); + + [Fact] + public void charge_port_latch() => + _sut.ChargePortLatch.Should().Be(_json["charge_port_latch"].Value()); + + [Fact] + public void charge_current_request() => + _sut.ChargeCurrentRequest.Should().Be(_json["charge_current_request"].Value()); + + [Fact] + public void charge_current_request_max() => + _sut.ChargeCurrentRequestMax.Should().Be(_json["charge_current_request_max"].Value()); + + [Fact] + public void managed_charging_active() => + _sut.ManagedChargingActive.Should().Be(_json["managed_charging_active"].Value()); + + [Fact] + public void managed_charging_user_canceled() => + _sut.ManagedChargingUserCanceled.Should().Be(_json["managed_charging_user_canceled"].Value()); + + [Fact] + public void managed_charging_start_time() => + _sut.ManagedChargingStartTime.Should().Be(_json["managed_charging_start_time"].Value()); + + [Fact] + public void battery_heater_on() => + _sut.BatteryHeaterOn.Should().Be(_json["battery_heater_on"].Value()); + + [Fact] + public void not_enough_power_to_heat() => + _sut.NotEnoughPowerToHeat.Should().Be(_json["not_enough_power_to_heat"].Value()); + + [Fact] + public void timestamp() => + _sut.Timestamp.Should().Be(_json["timestamp"].Value()); + } + + public class When_deserializing_ChargeState_with_minimal_data_Should_default + { + private readonly ChargeState _sut; + private readonly JObject _json; + + public When_deserializing_ChargeState_with_minimal_data_Should_default(ITestOutputHelper output) + { + _json = SampleJson.ChargeStateMinimal; + _sut = _json.ToObject(); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + _json); + } + + [Fact] + public void charging_state() => _sut.ChargingState.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void fast_charger_type() => _sut.FastChargerType.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void fast_charger_brand() => _sut.FastChargerBrand.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void charge_limit_soc() => _sut.ChargeLimitSoc.Should().Be(default(long)); + + [Fact] + public void charge_limit_soc_std() => _sut.ChargeLimitSocStd.Should().Be(default(long)); + + [Fact] + public void charge_limit_soc_min() => _sut.ChargeLimitSocMin.Should().Be(default(long)); + + [Fact] + public void charge_limit_soc_max() => _sut.ChargeLimitSocMax.Should().Be(default(long)); + + [Fact] + public void charge_to_max_range() => _sut.ChargeToMaxRange.Should().Be(default(bool)); + + [Fact] + public void max_range_charge_counter() => _sut.MaxRangeChargeCounter.Should().Be(default(long)); + + [Fact] + public void fast_charger_present() => _sut.FastChargerPresent.Should().Be(default(bool)); + + [Fact] + public void battery_range() => _sut.BatteryRange.Should().Be(default(double)); + + [Fact] + public void est_battery_range() => _sut.EstBatteryRange.Should().Be(default(double)); + + [Fact] + public void ideal_battery_range() => _sut.IdealBatteryRange.Should().Be(default(double)); + + [Fact] + public void battery_level() => _sut.BatteryLevel.Should().Be(default(long)); + + [Fact] + public void usable_battery_level() => _sut.UsableBatteryLevel.Should().Be(default(long)); + + [Fact] + public void charge_energy_added() => _sut.ChargeEnergyAdded.Should().Be(default(double)); + + [Fact] + public void charge_miles_added_rated() => _sut.ChargeMilesAddedRated.Should().Be(default(double)); + + [Fact] + public void charge_miles_added_ideal() => _sut.ChargeMilesAddedIdeal.Should().Be(default(long)); + + [Fact] + public void charger_voltage() => _sut.ChargerVoltage.Should().Be(default(long)); + + [Fact] + public void charger_pilot_current() => _sut.ChargerPilotCurrent.Should().Be(default(long)); + + [Fact] + public void charger_actual_current() => _sut.ChargerActualCurrent.Should().Be(default(long)); + + [Fact] + public void charger_power() => _sut.ChargerPower.Should().Be(default(long)); + + [Fact] + public void time_to_full_charge() => _sut.TimeToFullCharge.Should().Be(default(long)); + + [Fact] + public void trip_charging() => _sut.TripCharging.Should().Be(default(bool)); + + [Fact] + public void charge_rate() => _sut.ChargeRate.Should().Be(default(long)); + + [Fact] + public void charge_port_door_open() => _sut.ChargePortDoorOpen.Should().Be(default(bool)); + + [Fact] + public void conn_charge_cable() => _sut.ConnChargeCable.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void scheduled_charging_start_time() => _sut.ScheduledChargingStartTime.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void scheduled_charging_pending() => _sut.ScheduledChargingPending.Should().Be(default(bool)); + + [Fact] + public void user_charge_enable_request() => _sut.UserChargeEnableRequest.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void charge_enable_request() => _sut.ChargeEnableRequest.Should().Be(default(bool)); + + [Fact] + public void charger_phases() => _sut.ChargerPhases.Should().Be(default(int?)); + + [Fact] + public void charge_port_latch() => _sut.ChargePortLatch.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void charge_current_request() => _sut.ChargeCurrentRequest.Should().Be(default(long)); + + [Fact] + public void charge_current_request_max() => _sut.ChargeCurrentRequestMax.Should().Be(default(long)); + + [Fact] + public void managed_charging_active() => _sut.ManagedChargingActive.Should().Be(default(bool)); + + [Fact] + public void managed_charging_user_canceled() => _sut.ManagedChargingUserCanceled.Should().Be(default(bool)); + + [Fact] + public void managed_charging_start_time() => _sut.ManagedChargingStartTime.Should().NotBeNull().And.BeEmpty(); + + [Fact] + public void battery_heater_on() => _sut.BatteryHeaterOn.Should().Be(default(bool)); + + [Fact] + public void not_enough_power_to_heat() => _sut.NotEnoughPowerToHeat.Should().Be(default(bool)); + + [Fact] + public void timestamp() => _sut.Timestamp.Should().Be(default(long)); + } + + public class When_running_in_the_debugger_ChargeState_Should : DebuggerDisplayTestsBase + { + private readonly ChargeState _sut; + + public When_running_in_the_debugger_ChargeState_Should(ITestOutputHelper output) + : base(output) + { + _sut = Fixture.Create(); + GetDebuggerDisplay(_sut); + } + + [Fact] + public void include_the_charging_state_in_the_debugger_display() + { + DebuggerDisplayText.Should().Contain(_sut.ChargingState); + } + + [Fact] + public void include_the_battery_level_in_the_debugger_display() + { + DebuggerDisplayText.Should().Contain(_sut.BatteryLevel.ToString()); + } + + [Fact] + public void include_the_est_battery_range_in_the_debugger_display() + { + DebuggerDisplayText.Should().Contain(_sut.EstBatteryRange.ToString(CultureInfo.InvariantCulture)); + } + } + + public class ChargeState_Should_calculate + { + private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); + + private readonly ChargeState _sut; + + public ChargeState_Should_calculate(ITestOutputHelper output) + { + JObject json = SampleJson.ChargeState; + _sut = json.ToObject(); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + json); + } + + [Fact] + public void TimestampUtc() => _sut.TimestampUtc.Should().Be(Epoch.AddMilliseconds(_sut.Timestamp)); + } +} diff --git a/test/Tesla.NET.Tests/Models/GetChargeStateResponse.json b/test/Tesla.NET.Tests/Models/GetChargeStateResponse.json new file mode 100644 index 0000000..529950f --- /dev/null +++ b/test/Tesla.NET.Tests/Models/GetChargeStateResponse.json @@ -0,0 +1,45 @@ +{ + "response": { + "charging_state": "Charging", + "fast_charger_type": "ACSingleWireCAN", + "fast_charger_brand": "", + "charge_limit_soc": 90, + "charge_limit_soc_std": 90, + "charge_limit_soc_min": 50, + "charge_limit_soc_max": 100, + "charge_to_max_range": false, + "max_range_charge_counter": 0, + "fast_charger_present": false, + "battery_range": 110.29, + "est_battery_range": 79.79, + "ideal_battery_range": 88.12, + "battery_level": 37, + "usable_battery_level": 37, + "charge_energy_added": 7.28, + "charge_miles_added_rated": 30, + "charge_miles_added_ideal": 24, + "charger_voltage": 250, + "charger_pilot_current": 16, + "charger_actual_current": 9, + "charger_power": 7, + "time_to_full_charge": 6.25, + "trip_charging": false, + "charge_rate": 19.7, + "charge_port_door_open": true, + "conn_charge_cable": "IEC", + "scheduled_charging_start_time": "unknown scheduled_charging_start_time", + "scheduled_charging_pending": false, + "user_charge_enable_request": "unknown user_charge_enable_request", + "charge_enable_request": true, + "charger_phases": 3, + "charge_port_latch": "Engaged", + "charge_current_request": 9, + "charge_current_request_max": 16, + "managed_charging_active": false, + "managed_charging_user_canceled": false, + "managed_charging_start_time": "unknown managed_charging_start_time", + "battery_heater_on": false, + "not_enough_power_to_heat": false, + "timestamp": 1515396974152 + } +} \ No newline at end of file diff --git a/test/Tesla.NET.Tests/Models/SampleJson.cs b/test/Tesla.NET.Tests/Models/SampleJson.cs index aee81a0..6f462cc 100644 --- a/test/Tesla.NET.Tests/Models/SampleJson.cs +++ b/test/Tesla.NET.Tests/Models/SampleJson.cs @@ -31,10 +31,16 @@ public static TJson Load(string fileName) public static JObject AccessTokenResponse => Load(nameof(AccessTokenResponse)); + public static JObject ChargeState => (JObject)GetChargeStateResponse["response"]; + + public static JObject ChargeStateMinimal => new JObject(); + public static JObject DriveState => (JObject)GetDriveStateResponse["response"]; public static JObject DriveStateMinimal => new JObject(); + public static JObject GetChargeStateResponse => Load(nameof(GetChargeStateResponse)); + public static JObject GetDriveStateResponse => Load(nameof(GetDriveStateResponse)); public static JObject GetVehiclesResponse => Load(nameof(GetVehiclesResponse)); diff --git a/test/Tesla.NET.Tests/Tesla.NET.Tests.csproj b/test/Tesla.NET.Tests/Tesla.NET.Tests.csproj index 0fb7ac1..c7f305f 100644 --- a/test/Tesla.NET.Tests/Tesla.NET.Tests.csproj +++ b/test/Tesla.NET.Tests/Tesla.NET.Tests.csproj @@ -23,6 +23,7 @@ + From 39b43659a4b9ba9fdd4950f895ac232dc29e5792 Mon Sep 17 00:00:00 2001 From: James Skimming Date: Mon, 8 Jan 2018 09:32:01 +0000 Subject: [PATCH 2/2] Added the Get Charge State API --- src/Tesla.NET/ITeslaClient.cs | 45 ++++- .../Requests/HttpClientExtensions.cs | 36 ++++ src/Tesla.NET/TeslaClient.cs | 28 ++- test/Tesla.NET.Tests/GetChargeStateTests.cs | 178 ++++++++++++++++++ .../Models/GetChargeStateResponseTests.cs | 72 +++++++ 5 files changed, 349 insertions(+), 10 deletions(-) create mode 100644 test/Tesla.NET.Tests/GetChargeStateTests.cs create mode 100644 test/Tesla.NET.Tests/Models/GetChargeStateResponseTests.cs diff --git a/src/Tesla.NET/ITeslaClient.cs b/src/Tesla.NET/ITeslaClient.cs index d08cefe..3643d4e 100644 --- a/src/Tesla.NET/ITeslaClient.cs +++ b/src/Tesla.NET/ITeslaClient.cs @@ -38,21 +38,21 @@ Task>>> GetVehiclesAs CancellationToken cancellationToken = default); /// - /// Gets the of the with the specified + /// Gets the of the with the specified /// . /// /// The unique of a . /// A to observe while waiting for a task to /// complete. /// - /// The of the with the specified . + /// The of the with the specified . /// - Task>> GetVehicleStateAsync( + Task>> GetChargeStateAsync( long vehicleId, CancellationToken cancellationToken = default); /// - /// Gets the of the with the specified + /// Gets the of the with the specified /// . /// /// The unique of a . @@ -63,9 +63,9 @@ Task>> GetVehicleStateAsync( /// A to observe while waiting for a task to /// complete. /// - /// The of the with the specified . + /// The of the with the specified . /// - Task>> GetVehicleStateAsync( + Task>> GetChargeStateAsync( long vehicleId, string accessToken, CancellationToken cancellationToken = default); @@ -102,5 +102,38 @@ Task>> GetDriveStateAsync( long vehicleId, string accessToken, CancellationToken cancellationToken = default); + + /// + /// Gets the of the with the specified + /// . + /// + /// The unique of a . + /// A to observe while waiting for a task to + /// complete. + /// + /// The of the with the specified . + /// + Task>> GetVehicleStateAsync( + long vehicleId, + CancellationToken cancellationToken = default); + + /// + /// Gets the of the with the specified + /// . + /// + /// The unique of a . + /// + /// The access token used to authenticate the request; can be if the authentication is + /// added by default. + /// + /// A to observe while waiting for a task to + /// complete. + /// + /// The of the with the specified . + /// + Task>> GetVehicleStateAsync( + long vehicleId, + string accessToken, + CancellationToken cancellationToken = default); } } diff --git a/src/Tesla.NET/Requests/HttpClientExtensions.cs b/src/Tesla.NET/Requests/HttpClientExtensions.cs index d020ac5..71164d6 100644 --- a/src/Tesla.NET/Requests/HttpClientExtensions.cs +++ b/src/Tesla.NET/Requests/HttpClientExtensions.cs @@ -150,6 +150,42 @@ public static Task>>> .ReadJsonAsAsync>>(cancellationToken); } + /// + /// Gets the of the with the specified + /// . + /// + /// The . + /// The base of the Tesla Owner API. + /// The unique of a . + /// + /// The access token used to authenticate the request; can be if the authentication is + /// added by default. + /// + /// A to observe while waiting for a task to + /// complete. + /// + /// The of the with the specified . + /// + public static Task>> GetChargeStateAsync( + this HttpClient client, + Uri baseUri, + long vehicleId, + string accessToken = null, + CancellationToken cancellationToken = default) + { + if (client == null) + throw new ArgumentNullException(nameof(client)); + if (baseUri == null) + throw new ArgumentNullException(nameof(baseUri)); + + Uri requestUri = new Uri(baseUri, $"api/1/vehicles/{vehicleId}/data_request/charge_state"); + + return + client + .GetWithAuthAsync(requestUri, accessToken, cancellationToken) + .ReadJsonAsAsync>(cancellationToken); + } + /// /// Gets the of the with the specified /// . diff --git a/src/Tesla.NET/TeslaClient.cs b/src/Tesla.NET/TeslaClient.cs index 06dd642..c8a86ea 100644 --- a/src/Tesla.NET/TeslaClient.cs +++ b/src/Tesla.NET/TeslaClient.cs @@ -72,15 +72,15 @@ public Task>>> GetVeh } /// - public Task>> GetVehicleStateAsync( + public Task>> GetChargeStateAsync( long vehicleId, CancellationToken cancellationToken = default) { - return Client.GetVehicleStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken); + return Client.GetChargeStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken); } /// - public Task>> GetVehicleStateAsync( + public Task>> GetChargeStateAsync( long vehicleId, string accessToken, CancellationToken cancellationToken = default) @@ -88,7 +88,7 @@ public Task>> GetVehicleStateA if (string.IsNullOrWhiteSpace(accessToken)) throw new ArgumentNullException(nameof(accessToken)); - return Client.GetVehicleStateAsync(BaseUri, vehicleId, accessToken, cancellationToken); + return Client.GetChargeStateAsync(BaseUri, vehicleId, accessToken, cancellationToken); } /// @@ -110,5 +110,25 @@ public Task>> GetDriveStateAsync return Client.GetDriveStateAsync(BaseUri, vehicleId, accessToken, cancellationToken); } + + /// + public Task>> GetVehicleStateAsync( + long vehicleId, + CancellationToken cancellationToken = default) + { + return Client.GetVehicleStateAsync(BaseUri, vehicleId, cancellationToken: cancellationToken); + } + + /// + public Task>> GetVehicleStateAsync( + long vehicleId, + string accessToken, + CancellationToken cancellationToken = default) + { + if (string.IsNullOrWhiteSpace(accessToken)) + throw new ArgumentNullException(nameof(accessToken)); + + return Client.GetVehicleStateAsync(BaseUri, vehicleId, accessToken, cancellationToken); + } } } diff --git a/test/Tesla.NET.Tests/GetChargeStateTests.cs b/test/Tesla.NET.Tests/GetChargeStateTests.cs new file mode 100644 index 0000000..e682cf2 --- /dev/null +++ b/test/Tesla.NET.Tests/GetChargeStateTests.cs @@ -0,0 +1,178 @@ +// Copyright (c) 2018 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Tesla.NET +{ + using System; + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Net.Http; + using System.Threading.Tasks; + using AutoFixture; + using FluentAssertions; + using Newtonsoft.Json; + using Newtonsoft.Json.Linq; + using Tesla.NET.Models; + using Xunit; + using Xunit.Abstractions; + + public abstract class GetChargeStateSuccessTestsBase : ClientRequestContext + { + private readonly ResponseDataWrapper _expected; + private readonly long _vehicleId; + private readonly Uri _expectedRequestUri; + + protected GetChargeStateSuccessTestsBase(ITestOutputHelper output, bool useCustomBaseUri) + : base(output, useCustomBaseUri) + { + // Arrange + _expected = Fixture.Create>(); + _vehicleId = Fixture.Create(); + Handler.SetResponseContent(_expected); + _expectedRequestUri = new Uri(BaseUri, $"/api/1/vehicles/{_vehicleId}/data_request/charge_state"); + } + + [Fact] + public async Task Should_make_a_GET_request() + { + // Act + await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false); + + // Assert + Handler.Request.Method.Should().Be(HttpMethod.Get); + } + + [Fact] + public async Task Should_request_the_charge_state_endpoint() + { + // Act + await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false); + + // Assert + Handler.Request.RequestUri.Should().Be(_expectedRequestUri); + } + + [Fact] + public async Task Should_return_the_expected_charge_state() + { + // Act + MessageResponse> actual = + await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false); + + // Assert + actual.HttpStatusCode.Should().Be(HttpStatusCode.OK); + actual.Data.ShouldBeEquivalentTo(_expected, WithStrictOrdering); + } + + [Fact] + public async Task Should_set_the_bearer_token_with_the_specified_access_token() + { + // Act + await Sut.GetChargeStateAsync(_vehicleId, AccessToken).ConfigureAwait(false); + + // Assert + Handler.Request.Headers.Authorization.Scheme.Should().Be("Bearer"); + Handler.Request.Headers.Authorization.Parameter.Should().Be(AccessToken); + } + + [Fact] + public async Task Should_NOT_set_the_bearer_token_if_the_access_token_is_not_specified() + { + // Act + await Sut.GetChargeStateAsync(_vehicleId).ConfigureAwait(false); + + // Assert + Handler.Request.Headers.Authorization.Should().BeNull(); + } + } + + public class When_getting_the_charge_state_for_a_vehicle_using_the_default_base_Uri : GetChargeStateSuccessTestsBase + { + public When_getting_the_charge_state_for_a_vehicle_using_the_default_base_Uri(ITestOutputHelper output) + : base(output, useCustomBaseUri: false) + { + } + } + + public class When_getting_the_charge_state_for_a_vehicle_using_a_custom_base_Uri : GetChargeStateSuccessTestsBase + { + public When_getting_the_charge_state_for_a_vehicle_using_a_custom_base_Uri(ITestOutputHelper output) + : base(output, useCustomBaseUri: true) + { + } + } + + public abstract class GetChargeStateFailureTestsBase : ClientRequestContext + { + private readonly long _vehicleId; + + protected GetChargeStateFailureTestsBase(ITestOutputHelper output, bool useCustomBaseUri) + : base(output, useCustomBaseUri) + { + // Arrange + _vehicleId = Fixture.Create(); + Handler.SetResponseContent(new JObject(), HttpStatusCode.BadGateway); + } + + [Fact] + public void Should_throw_an_HttpRequestException() + { + // Act + Func action = () => Sut.GetChargeStateAsync(_vehicleId, AccessToken); + + // Assert + action.ShouldThrowExactly(); + } + } + + public class When_failing_to_get_the_charge_state_for_a_vehicle_using_the_default_base_Uri + : GetChargeStateFailureTestsBase + { + public When_failing_to_get_the_charge_state_for_a_vehicle_using_the_default_base_Uri(ITestOutputHelper output) + : base(output, useCustomBaseUri: false) + { + } + } + + public class When_failing_to_get_the_charge_state_for_a_vehicle_using_a_custom_base_Uri + : GetChargeStateFailureTestsBase + { + public When_failing_to_get_the_charge_state_for_a_vehicle_using_a_custom_base_Uri(ITestOutputHelper output) + : base(output, useCustomBaseUri: true) + { + } + } + + public class When_getting_the_charge_state_for_a_vehicle_the_raw_JSON : ClientRequestContext + { + private readonly JObject _expected; + private readonly long _vehicleId; + + public When_getting_the_charge_state_for_a_vehicle_the_raw_JSON(ITestOutputHelper output) + : base(output, useCustomBaseUri: false) + { + // Arrange + _expected = SampleJson.GetChargeStateResponse; + _vehicleId = Fixture.Create(); + + // Add random values to test whether it is correctly passed through. + _expected["randomValue1"] = Fixture.Create("randomValue1"); + _expected["randomValue2"] = JObject.FromObject(new { fakeId = Guid.NewGuid() }); + _expected["response"]["randomValue3"] = Fixture.Create("randomValue3"); + + Handler.SetResponseContent(_expected); + } + + [Fact] + public async Task Should_be_passed_through_in_the_response() + { + // Act + MessageResponse> response = + await Sut.GetChargeStateAsync(_vehicleId).ConfigureAwait(false); + + // Assert + response.RawJsonAsString.Should().Be(_expected.ToString(Formatting.None)); + } + } +} diff --git a/test/Tesla.NET.Tests/Models/GetChargeStateResponseTests.cs b/test/Tesla.NET.Tests/Models/GetChargeStateResponseTests.cs new file mode 100644 index 0000000..2f340ba --- /dev/null +++ b/test/Tesla.NET.Tests/Models/GetChargeStateResponseTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) 2018 James Skimming. All rights reserved. +// Licensed under the Apache License, Version 2.0. See LICENSE in the project root for license information. + +namespace Tesla.NET.Models +{ + using System; + using System.Collections.Generic; + using System.Linq; + using AutoFixture; + using FluentAssertions; + using Newtonsoft.Json.Linq; + using Xunit; + using Xunit.Abstractions; + + public class When_serializing_GetChargeStateResponse_Should_serialize : FixtureContext + { + private readonly ResponseDataWrapper _sut; + private readonly JObject _json; + + public When_serializing_GetChargeStateResponse_Should_serialize(ITestOutputHelper output) + : base(output) + { + _sut = Fixture.Create>(); + _json = JObject.FromObject(_sut); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + _json); + } + + [Fact] + public void one_properties() => _json.Count.Should().Be(1); + } + + public class When_serializing_and_deserializing_GetChargeStateResponse : FixtureContext + { + private readonly ResponseDataWrapper _expected; + private readonly ResponseDataWrapper _actual; + + public When_serializing_and_deserializing_GetChargeStateResponse(ITestOutputHelper output) + : base(output) + { + _expected = Fixture.Create>(); + JObject json = JObject.FromObject(_expected); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + json); + + _actual = json.ToObject>(); + } + + [Fact] + public void Should_retain_all_properties() => _actual.ShouldBeEquivalentTo(_expected, WithStrictOrdering); + } + + public class When_deserializing_GetChargeStateResponse_Should_deserialize : FixtureContext + { + private readonly ResponseDataWrapper _sut; + private readonly JObject _json; + private readonly ChargeState _expectedResponse; + + public When_deserializing_GetChargeStateResponse_Should_deserialize(ITestOutputHelper output) + : base(output) + { + _json = SampleJson.GetChargeStateResponse; + _sut = _json.ToObject>(); + _expectedResponse = SampleJson.ChargeState.ToObject(); + + output.WriteLine("Serialized JSON:" + Environment.NewLine + _json); + } + + [Fact] + public void response() => _sut.Response.ShouldBeEquivalentTo(_expectedResponse, WithStrictOrdering); + } +}