< Summary

Information
Class: c:\Source 2025\CurrencyConverter\CurrencyConverter\src\Infrastructure\ExchangeProviders\Frankfurter\FrankfurterExchangeProvider.cs
Assembly: Default
File(s): c:\Source 2025\CurrencyConverter\CurrencyConverter\src\Infrastructure\ExchangeProviders\Frankfurter\FrankfurterExchangeProvider.cs
Line coverage
100%
Covered lines: 45
Uncovered lines: 0
Coverable lines: 45
Total lines: 75
Line coverage: 100%
Branch coverage
100%
Covered branches: 4
Total branches: 4
Branch coverage: 100%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

File(s)

c:\Source 2025\CurrencyConverter\CurrencyConverter\src\Infrastructure\ExchangeProviders\Frankfurter\FrankfurterExchangeProvider.cs

#LineLine coverage
 1using Domain.Common;
 2using Domain.Currencies;
 3using System.Net.Http.Json;
 4using System.Reflection;
 5using System.Text.Json;
 6using Microsoft.Extensions.Logging;
 7using Infrastructure.ExchangeProviders.Frankfurter.Models;
 8
 9namespace Infrastructure.ExchangeProviders.Frankfurter
 10{
 11    public class FrankfurterExchangeProvider : IExchangeProvider
 12    {
 13        private readonly ILogger<FrankfurterExchangeProvider> _logger;
 14        private readonly HttpClient _httpClient;
 1015        public FrankfurterExchangeProvider(HttpClient httpClient, ILogger<FrankfurterExchangeProvider> logger)
 1016        {
 1017            _logger = logger;
 1018            _httpClient = httpClient;
 1019        }
 20
 1221        public ExchangeProviderType ProviderType { get; } = ExchangeProviderType.Frankfurter;
 22
 23        public async Task<Result<CurrencySnapshot>> FindLatestAsync(CurrencyCode currencyCode)
 324        {
 25            try
 326            {
 327                var response = await _httpClient.GetFromJsonAsync<FrankfurterLatestResponse>($"v1/latest?base={currencyC
 28
 229                List<(string Code, decimal Amount)> expectedRates = response.Rates.GetType()
 230                  .GetProperties(BindingFlags.Public | BindingFlags.Instance)
 6031                  .Where(prop => prop.GetValue(response.Rates) != null)
 3132                  .Select(prop => (Code: prop.Name, Amount: Convert.ToDecimal(prop.GetValue(response.Rates))))
 233                  .ToList();
 34
 235                var result = CurrencySnapshot.Create(response.Base,
 236                    response.Date,
 237                    expectedRates);
 38
 239                return result.Value;
 40            }
 141            catch (JsonException exception)
 142            {
 143                _logger.LogError("Franfurter returned an invalid json payload, {error}", exception.Message);
 144                return Result.Failure<CurrencySnapshot>(Error.SystemError);
 45            }
 346        }
 47
 48        public async Task<Result<List<CurrencySnapshot>>> SearchAsync(CurrencyCode currencyCode, DateTime startDate, Dat
 449        {
 50            try
 451            {
 452                var response = await _httpClient.GetFromJsonAsync<FrankfurterSearchResponse>($"v1/{startDate.ToString("y
 353                List<CurrencySnapshot> result = new List<CurrencySnapshot>();
 3354                foreach (var rate in response.Rates)
 1255                {
 1256                    var snapShotResult =
 1257                    CurrencySnapshot.Create(
 1258                     currencyCode.Value,
 1259                     rate.Key,
 3260                     rate.Value.Select(r => (r.Key, r.Value)).ToList());
 1261                    if (snapShotResult.IsSuccess)
 1262                    {
 1263                        result.Add(snapShotResult.Value);
 1264                    }
 1265                }
 366                return result;
 67            }
 168            catch (JsonException exception)
 169            {
 170                _logger.LogError("Franfurter returned an invalid json payload, {error}", exception.Message);
 171                return Result.Failure<List<CurrencySnapshot>>(Error.SystemError);
 72            }
 473        }
 74    }
 75}