Skip to content

Commit

Permalink
Introduced a settings proxy for our code to rely on rather than needi…
Browse files Browse the repository at this point in the history
…ng to directly access the settings object with its additiona noise around json and property notify.
  • Loading branch information
Delubear committed Sep 25, 2024
1 parent c91599c commit 2e93337
Show file tree
Hide file tree
Showing 20 changed files with 314 additions and 151 deletions.
94 changes: 37 additions & 57 deletions GlucoseTray.Tests/AlertServiceTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
using GlucoseTray.Models;
using GlucoseTray.Enums;
using GlucoseTray.Services;
using Microsoft.Extensions.Options;
using NSubstitute;
using GlucoseTray.Settings;

namespace GlucoseTray.Tests;

Expand All @@ -17,14 +17,11 @@ public class AlertServiceTests
public void AlertNotification_WhenHighAlertTriggered_ShouldShowHighAlert(GlucoseUnitType unitType, int mgValue, double mmolValue, double alertValue)
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
HighAlert = true,
HighBg = alertValue,
GlucoseUnit = unitType,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.HighAlert.Returns(true);
options.HighBg.Returns(alertValue);
options.GlucoseUnit.Returns(unitType);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -49,14 +46,11 @@ public void AlertNotification_WhenHighAlertTriggered_ShouldShowHighAlert(Glucose
public void AlertNotification_WhenWarningHighAlertTriggered_ShouldShowWarningHighAlert(GlucoseUnitType unitType, int mgValue, double mmolValue, double alertValue)
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
WarningHighAlert = true,
WarningHighBg = alertValue,
GlucoseUnit = unitType,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.WarningHighAlert.Returns(true);
options.WarningHighBg.Returns(alertValue);
options.GlucoseUnit.Returns(unitType);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -81,14 +75,11 @@ public void AlertNotification_WhenWarningHighAlertTriggered_ShouldShowWarningHig
public void AlertNotification_WhenCriticalLowAlertTriggered_ShouldShowCriticalLowAlert(GlucoseUnitType unitType, int mgValue, double mmolValue, double alertValue)
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
CriticallyLowAlert = true,
CriticalLowBg = alertValue,
GlucoseUnit = unitType,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.CriticalLowAlert.Returns(true);
options.CriticalLowBg.Returns(alertValue);
options.GlucoseUnit.Returns(unitType);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -113,14 +104,12 @@ public void AlertNotification_WhenCriticalLowAlertTriggered_ShouldShowCriticalLo
public void AlertNotification_WhenLowAlertTriggered_ShouldShowLowAlert(GlucoseUnitType unitType, int mgValue, double mmolValue, double alertValue)
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
LowAlert = true,
LowBg = alertValue,
GlucoseUnit = unitType,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.LowAlert.Returns(true);
options.LowBg.Returns(alertValue);
options.GlucoseUnit.Returns(unitType);
options.StaleResultsThreshold.Returns(15);

var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -145,14 +134,11 @@ public void AlertNotification_WhenLowAlertTriggered_ShouldShowLowAlert(GlucoseUn
public void AlertNotification_WhenWarningLowAlertTriggered_ShouldShowWarningLowAlert(GlucoseUnitType unitType, int mgValue, double mmolValue, double alertValue)
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
WarningLowAlert = true,
WarningLowBg = alertValue,
GlucoseUnit = unitType,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.WarningLowAlert.Returns(true);
options.WarningLowBg.Returns(alertValue);
options.GlucoseUnit.Returns(unitType);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -173,14 +159,11 @@ public void AlertNotification_WhenWarningLowAlertTriggered_ShouldShowWarningLowA
public void AlertNotification_WhenNoAlertTriggered_ShouldNotShowAlert()
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
HighAlert = true,
HighBg = 200,
GlucoseUnit = GlucoseUnitType.MG,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.HighAlert.Returns(true);
options.HighBg.Returns(200);
options.GlucoseUnit.Returns(GlucoseUnitType.MG);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand All @@ -202,14 +185,11 @@ public void AlertNotification_WhenNoAlertTriggered_ShouldNotShowAlert()
public void AlertNotification_WhenStale_ShouldNotShowAlert()
{
// Arrange
var options = Substitute.For<IOptionsMonitor<GlucoseTraySettings>>();
options.CurrentValue.Returns(new GlucoseTraySettings
{
HighAlert = true,
HighBg = 200,
GlucoseUnit = GlucoseUnitType.MG,
StaleResultsThreshold = 15,
});
var options = Substitute.For<ISettingsProxy>();
options.HighAlert.Returns(true);
options.HighBg.Returns(200);
options.GlucoseUnit.Returns(GlucoseUnitType.MG);
options.StaleResultsThreshold.Returns(15);
var uiService = Substitute.For<IUiService>();
var alertService = new AlertService(options, uiService);
var glucoseResult = new GlucoseResult
Expand Down
10 changes: 5 additions & 5 deletions GlucoseTray/AppContext.cs
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using GlucoseTray.Settings;
using Microsoft.Extensions.Logging;
using System.Windows.Forms;

namespace GlucoseTray;

public class AppContext : ApplicationContext
{
private readonly ILogger<AppContext> _logger;
private readonly IOptionsMonitor<GlucoseTraySettings> _options;
private readonly ISettingsProxy _options;
private readonly IGlucoseFetchService _fetchService;
private readonly NotifyIcon _trayIcon;
private readonly IUiService _uiService;
private readonly AlertService _alertService;

public AppContext(ILogger<AppContext> logger, IGlucoseFetchService fetchService, IOptionsMonitor<GlucoseTraySettings> options, IUiService uiService, AlertService alertService)
public AppContext(ILogger<AppContext> logger, IGlucoseFetchService fetchService, ISettingsProxy options, IUiService uiService, AlertService alertService)
{
_logger = logger;
_fetchService = fetchService;
Expand All @@ -37,7 +37,7 @@ private async void BeginCycle()
_uiService.CreateIcon(currentGlucoseResult);
_alertService.AlertNotification(currentGlucoseResult);

await Task.Delay(_options.CurrentValue.PollingThresholdTimeSpan);
await Task.Delay(_options.PollingThresholdTimeSpan);
}
catch (Exception e)
{
Expand Down
4 changes: 3 additions & 1 deletion GlucoseTray/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using GlucoseTray.Views.Settings;
using GlucoseTray.Settings;
using GlucoseTray.Views.Settings;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
Expand Down Expand Up @@ -54,6 +55,7 @@ private static void ConfigureServices(IConfiguration configuration, IServiceColl
.AddScoped<IExternalCommunicationAdapter, ExternalCommunicationAdapter>()
.AddScoped<DebugService, DebugService>()
.AddScoped<ISettingsWindowService, SettingsWindowService>()
.AddScoped<ISettingsProxy, SettingsProxy>()
.AddScoped<IGlucoseFetchService, GlucoseFetchService>();
}

Expand Down
20 changes: 10 additions & 10 deletions GlucoseTray/Services/AlertService.cs
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
using Microsoft.Extensions.Options;
using GlucoseTray.Settings;

namespace GlucoseTray.Services;

public class AlertService(IOptionsMonitor<GlucoseTraySettings> options, IUiService uiService)
public class AlertService(ISettingsProxy options, IUiService uiService)
{
private readonly IOptionsMonitor<GlucoseTraySettings> _options = options;
private readonly ISettingsProxy _options = options;
private readonly IUiService _uiService = uiService;
private AlertLevel _currentAlertLevel = AlertLevel.None;

public void AlertNotification(GlucoseResult currentGlucoseResult)
{
if (currentGlucoseResult.IsStale(_options.CurrentValue.StaleResultsThreshold))
if (currentGlucoseResult.IsStale(_options.StaleResultsThreshold))
return;

var highAlertTriggered = _options.CurrentValue.HighAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CurrentValue.HighBg, UpDown.Down);
var warningHighAlertTriggered = _options.CurrentValue.WarningHighAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CurrentValue.WarningHighBg, UpDown.Down);
var warningLowAlertTriggered = _options.CurrentValue.WarningLowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CurrentValue.WarningLowBg, UpDown.Up);
var lowAlertTriggered = _options.CurrentValue.LowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CurrentValue.LowBg, UpDown.Up);
var criticalLowAlertTriggered = _options.CurrentValue.CriticallyLowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CurrentValue.CriticalLowBg, UpDown.Up);
var highAlertTriggered = _options.HighAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.HighBg, UpDown.Down);
var warningHighAlertTriggered = _options.WarningHighAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.WarningHighBg, UpDown.Down);
var warningLowAlertTriggered = _options.WarningLowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.WarningLowBg, UpDown.Up);
var lowAlertTriggered = _options.LowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.LowBg, UpDown.Up);
var criticalLowAlertTriggered = _options.CriticalLowAlert && IsAlertTriggered(currentGlucoseResult.MgValue, currentGlucoseResult.MmolValue, _options.CriticalLowBg, UpDown.Up);

// Order matters. We need to show the most severe alert while avoid multiple alerts. (High > warning high. Critical > low > warning low)
if (highAlertTriggered)
Expand Down Expand Up @@ -62,7 +62,7 @@ private bool IsAlertTriggered(double glucoseValueMG, double glucoseValueMMOL, do
{
if (glucoseValueMMOL == 0) // If a null / default result is returned, do not trigger alerts.
return false;
if (_options.CurrentValue.GlucoseUnit == GlucoseUnitType.MG)
if (_options.GlucoseUnit == GlucoseUnitType.MG)
{
if (directionGlucoseShouldBeToNotAlert == UpDown.Down)
return glucoseValueMG >= alertThreshold;
Expand Down
18 changes: 9 additions & 9 deletions GlucoseTray/Services/DexcomService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using GlucoseTray.Settings;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Text.Json;

Expand All @@ -12,13 +12,13 @@ public interface IDexcomService

public class DexcomService : IDexcomService
{
private readonly IOptionsMonitor<GlucoseTraySettings> _options;
private readonly ISettingsProxy _options;
private readonly ILogger _logger;
private readonly UrlAssembler _urlBuilder;
private readonly IExternalCommunicationAdapter _externalAdapter;
private readonly DebugService _debug;

public DexcomService(IOptionsMonitor<GlucoseTraySettings> options, ILogger<DexcomService> logger, UrlAssembler urlBuilder, IExternalCommunicationAdapter externalAdapter, DebugService debug)
public DexcomService(ISettingsProxy options, ILogger<DexcomService> logger, UrlAssembler urlBuilder, IExternalCommunicationAdapter externalAdapter, DebugService debug)
{
_options = options;
_logger = logger;
Expand Down Expand Up @@ -50,7 +50,7 @@ public async Task<GlucoseResult> GetLatestReadingAsync()
catch (Exception ex)
{
_logger.LogError(ex, "Dexcom fetching failed or received incorrect format.");
if (_options.CurrentValue.IsDebugMode)
if (_options.IsDebugMode)
_debug.ShowDebugAlert(ex, "Dexcom result fetch");

glucoseResult = GlucoseResult.Default;
Expand All @@ -66,7 +66,7 @@ private GlucoseResult MapToResult(DexcomResult data)
var unixTime = string.Join("", data.ST.Where(char.IsDigit));
var trend = data.Trend;

GlucoseMath.CalculateValues(result, data.Value, _options.CurrentValue);
GlucoseMath.CalculateValues(result, data.Value, _options);
result.DateTimeUTC = !string.IsNullOrWhiteSpace(unixTime) ? DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(unixTime)).UtcDateTime : DateTime.MinValue;
result.Trend = trend.GetTrend();
result.Source = FetchMethod.DexcomShare;
Expand All @@ -86,7 +86,7 @@ private async Task<string> GetSessionId(string accountId)
{
accountId = accountId,
applicationId = "d8665ade-9673-4e27-9ff6-92db4ce13d13",
password = _options.CurrentValue.DexcomPassword
password = _options.DexcomPassword
});

var sessionUrl = _urlBuilder.BuildDexComSessionUrl();
Expand All @@ -109,9 +109,9 @@ private async Task<string> GetAccountId()
{
var accountIdRequestJson = JsonSerializer.Serialize(new
{
accountName = _options.CurrentValue.DexcomUsername,
accountName = _options.DexcomUsername,
applicationId = "d8665ade-9673-4e27-9ff6-92db4ce13d13",
password = _options.CurrentValue.DexcomPassword
password = _options.DexcomPassword
});

var accountUrl = _urlBuilder.BuildDexComAccountIdUrl();
Expand Down
10 changes: 5 additions & 5 deletions GlucoseTray/Services/ExternalCommunicationAdapter.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using GlucoseTray.Settings;
using Microsoft.Extensions.Logging;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
Expand All @@ -17,9 +17,9 @@ public class ExternalCommunicationAdapter : IExternalCommunicationAdapter
private readonly IHttpClientFactory _httpClientFactory;
private readonly DebugService _debug;
private readonly ILogger _logger;
private readonly IOptionsMonitor<GlucoseTraySettings> _options;
private readonly ISettingsProxy _options;

public ExternalCommunicationAdapter(IHttpClientFactory httpClientFactory, ILogger<ExternalCommunicationAdapter> logger, IOptionsMonitor<GlucoseTraySettings> options, DebugService debug)
public ExternalCommunicationAdapter(IHttpClientFactory httpClientFactory, ILogger<ExternalCommunicationAdapter> logger, ISettingsProxy options, DebugService debug)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
Expand Down Expand Up @@ -71,7 +71,7 @@ private async Task<string> DoApiResponseAsync(HttpRequestMessage request)
{
_logger.LogError(ex, "Invalid external response.");
_debug.AddDebugText("Error with external communication: " + ex.Message);
if (_options.CurrentValue.IsDebugMode)
if (_options.IsDebugMode)
_debug.ShowDebugAlert(ex, "External result fetch");
throw;
}
Expand Down
10 changes: 5 additions & 5 deletions GlucoseTray/Services/GlucoseFetchService.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using GlucoseTray.Settings;
using Microsoft.Extensions.Logging;

namespace GlucoseTray.Services;

Expand All @@ -10,12 +10,12 @@ public interface IGlucoseFetchService

public class GlucoseFetchService : IGlucoseFetchService
{
private readonly IOptionsMonitor<GlucoseTraySettings> _options;
private readonly ISettingsProxy _options;
private readonly ILogger<GlucoseFetchService> _logger;
private readonly IDexcomService _dexcomService;
private readonly INightscoutService _nightscoutService;

public GlucoseFetchService(IOptionsMonitor<GlucoseTraySettings> options, ILogger<GlucoseFetchService> logger, IDexcomService dexcomService, INightscoutService nightscoutService)
public GlucoseFetchService(ISettingsProxy options, ILogger<GlucoseFetchService> logger, IDexcomService dexcomService, INightscoutService nightscoutService)
{
_logger = logger;
_options = options;
Expand All @@ -28,7 +28,7 @@ public async Task<GlucoseResult> GetLatestReadingsAsync()
var fetchResult = new GlucoseResult();
try
{
switch (_options.CurrentValue.FetchMethod)
switch (_options.FetchMethod)
{
case FetchMethod.DexcomShare:
fetchResult = await _dexcomService.GetLatestReadingAsync();
Expand Down
8 changes: 5 additions & 3 deletions GlucoseTray/Services/GlucoseMath.cs
Original file line number Diff line number Diff line change
@@ -1,16 +1,18 @@
namespace GlucoseTray.Services;
using GlucoseTray.Settings;

namespace GlucoseTray.Services;

internal static class GlucoseMath
{
private static bool IsCriticalLow(GlucoseResult result, GlucoseTraySettings currentSettings)
private static bool IsCriticalLow(GlucoseResult result, ISettingsProxy currentSettings)
{
if (result.MmolValue == 0) // Don't treat a zero / null / default result as critical low.
return false;
return (currentSettings.GlucoseUnit == GlucoseUnitType.MMOL && result.MmolValue <= currentSettings.CriticalLowBg)
|| (currentSettings.GlucoseUnit == GlucoseUnitType.MG && result.MgValue <= currentSettings.CriticalLowBg);
}

internal static void CalculateValues(GlucoseResult result, double value, GlucoseTraySettings currentSettings)
internal static void CalculateValues(GlucoseResult result, double value, ISettingsProxy currentSettings)
{
if (value == 0)
{
Expand Down
Loading

0 comments on commit 2e93337

Please sign in to comment.