diff --git a/Covid19Api.sln b/Covid19Api.sln index b49edcd..2fa085c 100644 --- a/Covid19Api.sln +++ b/Covid19Api.sln @@ -71,6 +71,8 @@ EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Covid19Api.AutoMapper.Tests", "test\Covid19Api.AutoMapper.Tests\Covid19Api.AutoMapper.Tests.csproj", "{7D85801F-6AF5-407B-B262-2F85E6D8CF7D}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Covid19Api.Services.Tests", "test\Covid19Api.Services.Tests\Covid19Api.Services.Tests.csproj", "{0D3D25E7-6045-41C1-B63A-AFCCFE93C403}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -336,6 +338,18 @@ Global {7D85801F-6AF5-407B-B262-2F85E6D8CF7D}.Release|x64.Build.0 = Release|Any CPU {7D85801F-6AF5-407B-B262-2F85E6D8CF7D}.Release|x86.ActiveCfg = Release|Any CPU {7D85801F-6AF5-407B-B262-2F85E6D8CF7D}.Release|x86.Build.0 = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|x64.ActiveCfg = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|x64.Build.0 = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|x86.ActiveCfg = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Debug|x86.Build.0 = Debug|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|Any CPU.Build.0 = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|x64.ActiveCfg = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|x64.Build.0 = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|x86.ActiveCfg = Release|Any CPU + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(NestedProjects) = preSolution {1A670B81-08F0-4F15-81AF-4DDD12E765D6} = {2A35F3E7-12D1-4F74-8867-F5882FB47009} @@ -359,5 +373,6 @@ Global {8C8534AB-D819-4C9B-BF63-C750646AF787} = {2A35F3E7-12D1-4F74-8867-F5882FB47009} {F135C222-3190-4379-A0B9-35A519E535A6} = {2A35F3E7-12D1-4F74-8867-F5882FB47009} {7D85801F-6AF5-407B-B262-2F85E6D8CF7D} = {EBCCA0C8-4218-490F-A131-E8DF265DC415} + {0D3D25E7-6045-41C1-B63A-AFCCFE93C403} = {EBCCA0C8-4218-490F-A131-E8DF265DC415} EndGlobalSection EndGlobal diff --git a/src/Covid19Api.Endpoints.Grpc/CountryStatisticsServiceGrpc.cs b/src/Covid19Api.Endpoints.Grpc/CountryStatisticsServiceGrpc.cs index 13ea9a5..8321962 100644 --- a/src/Covid19Api.Endpoints.Grpc/CountryStatisticsServiceGrpc.cs +++ b/src/Covid19Api.Endpoints.Grpc/CountryStatisticsServiceGrpc.cs @@ -62,7 +62,7 @@ public override async Task LoadHistoricalCountrySt CountryStatisticsForCountryGrpcMessage request, ServerCallContext context) { - var query = new LoadHistoricalCountryStatisticsForCountryQuery(request.Country); + var query = new LoadHistoricalCountryStatisticsForCountryQuery(request.Country, DateTime.UtcNow.Date.AddDays(-9)); var countryStatistics = await this.mediator.Send(query); return new CountryStatisticsGrpcMessage { diff --git a/src/Covid19Api.Endpoints.Rest/V1/CountryStatisticsController.cs b/src/Covid19Api.Endpoints.Rest/V1/CountryStatisticsController.cs index da3f98a..92769a3 100644 --- a/src/Covid19Api.Endpoints.Rest/V1/CountryStatisticsController.cs +++ b/src/Covid19Api.Endpoints.Rest/V1/CountryStatisticsController.cs @@ -28,13 +28,22 @@ public Task> LoadLatestAsync() => public Task> LoadHistoryAsync() => this.mediator.Send(new LoadHistoricalCountriesStatisticsQuery(DateTime.UtcNow.Date.AddDays(-9))); + [HttpGet("history/vary")] + public Task> LoadVaryHistoryAsync() + => this.mediator.Send(new CalculateVaryForCountriesStatisticsQuery(DateTime.UtcNow.Date.AddDays(-9))); + [HttpGet("{country}")] public Task LoadLatestForCountryAsync(string country) => this.mediator.Send(new LoadLatestStatisticsForCountryQuery(country)); [HttpGet("{country}/history")] public Task> LoadHistoryForCountryAsync(string country) => - this.mediator.Send(new LoadHistoricalCountryStatisticsForCountryQuery(country)); + this.mediator.Send( + new LoadHistoricalCountryStatisticsForCountryQuery(country, DateTime.UtcNow.Date.AddDays(-9))); + + [HttpGet("{country}/history/vary")] + public Task> LoadVaryHistoryForCountryAsync(string country) => + this.mediator.Send(new CalculateVaryForCountryStatisticsQuery(country, DateTime.UtcNow.Date.AddDays(-9))); [HttpGet("{countryCode}/flag")] public async Task LoadFlagAsync(string countryCode) diff --git a/src/Covid19Api.IoC/Extensions/ContainerBuilderExtensions.cs b/src/Covid19Api.IoC/Extensions/ContainerBuilderExtensions.cs index 5e8738d..949bcf8 100644 --- a/src/Covid19Api.IoC/Extensions/ContainerBuilderExtensions.cs +++ b/src/Covid19Api.IoC/Extensions/ContainerBuilderExtensions.cs @@ -2,8 +2,10 @@ using Covid19Api.IoC.Modules; using Covid19Api.Repositories; using Covid19Api.Repositories.Abstractions; +using Covid19Api.Services.Abstractions.Calculators; using Covid19Api.Services.Abstractions.Compression; using Covid19Api.Services.Abstractions.Loader; +using Covid19Api.Services.Calculators; using Covid19Api.Services.Compression; using Covid19Api.Services.Decorator; using Covid19Api.Services.Loader; @@ -60,6 +62,10 @@ public static ContainerBuilder RegisterRepositories(this ContainerBuilder builde public static ContainerBuilder RegisterServices(this ContainerBuilder builder) { + builder.RegisterType() + .As() + .SingleInstance(); + builder.RegisterType() .As() .SingleInstance(); diff --git a/src/Covid19Api.Presentation/Response/CountryVaryStatisticContainerDto.cs b/src/Covid19Api.Presentation/Response/CountryVaryStatisticContainerDto.cs new file mode 100644 index 0000000..942d3ac --- /dev/null +++ b/src/Covid19Api.Presentation/Response/CountryVaryStatisticContainerDto.cs @@ -0,0 +1,7 @@ +using System; +using System.Collections.Generic; + +namespace Covid19Api.Presentation.Response +{ + public record CountryVaryStatisticContainerDto(DateTime Time, IEnumerable Vary); +} \ No newline at end of file diff --git a/src/Covid19Api.Presentation/Response/CountryVaryStatisticDto.cs b/src/Covid19Api.Presentation/Response/CountryVaryStatisticDto.cs new file mode 100644 index 0000000..c60775d --- /dev/null +++ b/src/Covid19Api.Presentation/Response/CountryVaryStatisticDto.cs @@ -0,0 +1,4 @@ +namespace Covid19Api.Presentation.Response +{ + public record CountryVaryStatisticDto(string ValueType, double? Vary, int? ValueYesterday, int ValueToday); +} \ No newline at end of file diff --git a/src/Covid19Api.Services.Abstractions/Calculators/ICountryVaryStatisticsCalculator.cs b/src/Covid19Api.Services.Abstractions/Calculators/ICountryVaryStatisticsCalculator.cs new file mode 100644 index 0000000..90b37b3 --- /dev/null +++ b/src/Covid19Api.Services.Abstractions/Calculators/ICountryVaryStatisticsCalculator.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using Covid19Api.Domain; +using Covid19Api.Presentation.Response; + +namespace Covid19Api.Services.Abstractions.Calculators +{ + public interface ICountryVaryStatisticsCalculator + { + IEnumerable Calculate(IEnumerable countryStatistics); + } +} \ No newline at end of file diff --git a/src/Covid19Api.Services.Abstractions/Covid19Api.Services.Abstractions.csproj b/src/Covid19Api.Services.Abstractions/Covid19Api.Services.Abstractions.csproj index 76dbbcc..6c566d3 100644 --- a/src/Covid19Api.Services.Abstractions/Covid19Api.Services.Abstractions.csproj +++ b/src/Covid19Api.Services.Abstractions/Covid19Api.Services.Abstractions.csproj @@ -10,6 +10,7 @@ + diff --git a/src/Covid19Api.Services/Calculators/CountryVaryStatisticsCalculator.cs b/src/Covid19Api.Services/Calculators/CountryVaryStatisticsCalculator.cs new file mode 100644 index 0000000..4d69640 --- /dev/null +++ b/src/Covid19Api.Services/Calculators/CountryVaryStatisticsCalculator.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Covid19Api.Domain; +using Covid19Api.Presentation.Response; +using Covid19Api.Services.Abstractions.Calculators; + +namespace Covid19Api.Services.Calculators +{ + public class CountryVaryStatisticsCalculator : ICountryVaryStatisticsCalculator + { + public IEnumerable Calculate(IEnumerable countryStatistics) + { + var countryStatisticsByFetchedAt = countryStatistics + .OrderBy(statistic => statistic.FetchedAt) + .GroupBy(statistic => statistic.FetchedAt) + .ToList(); + + for (var i = 0; i < countryStatisticsByFetchedAt.Count; i++) + { + var currentGroup = countryStatisticsByFetchedAt.ElementAt(i); + + if (i == 0) + { + yield return CreateEmpty(currentGroup.Key.Date, currentGroup.ToList()); + continue; + } + + var previousGroup = countryStatisticsByFetchedAt.ElementAt(i - 1); + + yield return new CountryVaryStatisticContainerDto(currentGroup.Key.Date, Calculate(currentGroup.ToList(), previousGroup.ToList())); + } + } + + private static IEnumerable Calculate(IReadOnlyList current, + IReadOnlyList previous) + { + var currentTotalSum = current.Sum(c => c.TotalCases); + var previousTotalSum = previous.Sum(c => c.TotalCases); + yield return new CountryVaryStatisticDto(ValueKeys.Total, + CalculateVary(currentTotalSum, previousTotalSum), previousTotalSum, currentTotalSum); + + var currentNewSum = current.Sum(c => c.NewCases); + var previousNewSum = previous.Sum(c => c.NewCases); + yield return new CountryVaryStatisticDto(ValueKeys.New, + CalculateVary(currentNewSum, previousNewSum), previousNewSum, currentNewSum); + + var currentActiveSum = current.Sum(c => c.ActiveCases); + var previousActiveSum = previous.Sum(c => c.ActiveCases); + yield return new CountryVaryStatisticDto(ValueKeys.Active, + CalculateVary(currentActiveSum, previousActiveSum), previousActiveSum, currentActiveSum); + + var currentDeathsSum = current.Sum(c => c.TotalDeaths); + var previousDeathsSum = previous.Sum(c => c.TotalDeaths); + yield return new CountryVaryStatisticDto(ValueKeys.Deaths, + CalculateVary(currentDeathsSum, previousDeathsSum), previousDeathsSum, currentDeathsSum); + + var currentNewDeathsSum = current.Sum(c => c.NewDeaths); + var previousNewDeathsSum = previous.Sum(c => c.NewDeaths); + yield return new CountryVaryStatisticDto(ValueKeys.NewDeaths, + CalculateVary(currentNewDeathsSum, previousNewDeathsSum), previousNewDeathsSum, currentNewDeathsSum); + + var currentRecoveredSum = current.Sum(c => c.RecoveredCases); + var previousRecoveredSum = previous.Sum(c => c.RecoveredCases); + yield return new CountryVaryStatisticDto(ValueKeys.Recovered, + CalculateVary(currentRecoveredSum, previousRecoveredSum), previousRecoveredSum, currentRecoveredSum); + } + + private static double CalculateVary(int current, int previous) + { + return current > previous + ? CalculateIncrease(current, previous) + : CalculateDecrease(current, previous); + } + + private static double CalculateIncrease(int current, int previous) + { + var difference = current - previous; + return difference / (double) current * 100; + } + + private static double CalculateDecrease(int current, int previous) + { + var difference = previous - current; + var decrease = difference / (double) previous * 100; + + return decrease * -1; + } + + private static CountryVaryStatisticContainerDto CreateEmpty(DateTime fetchedAt, + IReadOnlyList currentStatistics) + { + return new(fetchedAt, new List + { + new(ValueKeys.Total, null, null, currentStatistics.Sum(c => c.TotalCases)), + new(ValueKeys.New, null, null, currentStatistics.Sum(c => c.NewCases)), + new(ValueKeys.Active, null, null, currentStatistics.Sum(c => c.ActiveCases)), + new(ValueKeys.Total, null, null, currentStatistics.Sum(c => c.TotalDeaths)), + new(ValueKeys.NewDeaths, null, null, currentStatistics.Sum(c => c.NewDeaths)), + new(ValueKeys.Recovered, null, null, currentStatistics.Sum(c => c.RecoveredCases)), + }); + } + } +} \ No newline at end of file diff --git a/src/Covid19Api.Services/Calculators/ValueKeys.cs b/src/Covid19Api.Services/Calculators/ValueKeys.cs new file mode 100644 index 0000000..5de916d --- /dev/null +++ b/src/Covid19Api.Services/Calculators/ValueKeys.cs @@ -0,0 +1,15 @@ +using System.Runtime.CompilerServices; + +[assembly: InternalsVisibleTo("Covid19Api.Services.Tests")] +namespace Covid19Api.Services.Calculators +{ + internal static class ValueKeys + { + public const string Total = "Total"; + public const string New = "New"; + public const string Active = "Active"; + public const string Deaths = "Deaths"; + public const string NewDeaths = "NewDeaths"; + public const string Recovered = "Recovered"; + } +} \ No newline at end of file diff --git a/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQuery.cs b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQuery.cs new file mode 100644 index 0000000..1f34a2b --- /dev/null +++ b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQuery.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Covid19Api.Presentation.Response; +using Covid19Api.UseCases.Abstractions.Base; +using Covid19Api.UseCases.Abstractions.Models; +using MediatR; + +namespace Covid19Api.UseCases.Abstractions.Queries.CountryStatistics +{ + public record CalculateVaryForCountriesStatisticsQuery(DateTime MinFetchedAt) : ICacheableRequest, IRequest> + { + public CacheConfiguration GetCacheConfiguration() => new(nameof(CalculateVaryForCountriesStatisticsQuery), TimeSpan.FromMinutes(30)); + } +} \ No newline at end of file diff --git a/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQuery.cs b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQuery.cs new file mode 100644 index 0000000..3e9c826 --- /dev/null +++ b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQuery.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using Covid19Api.Presentation.Response; +using Covid19Api.UseCases.Abstractions.Base; +using Covid19Api.UseCases.Abstractions.Models; +using MediatR; + +namespace Covid19Api.UseCases.Abstractions.Queries.CountryStatistics +{ + public record CalculateVaryForCountryStatisticsQuery(string Country, DateTime MinFetchedAt) : ICacheableRequest, IRequest> + { + public CacheConfiguration GetCacheConfiguration() => new(nameof(CalculateVaryForCountryStatisticsQuery), TimeSpan.FromMinutes(30)); + } +} \ No newline at end of file diff --git a/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQuery.cs b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQuery.cs index 410e46c..c79b32d 100644 --- a/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQuery.cs +++ b/src/Covid19Api.UseCases.Abstractions/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQuery.cs @@ -7,7 +7,7 @@ namespace Covid19Api.UseCases.Abstractions.Queries.CountryStatistics { - public sealed record LoadHistoricalCountryStatisticsForCountryQuery(string Country) : ICacheableRequest, + public sealed record LoadHistoricalCountryStatisticsForCountryQuery(string Country, DateTime MinFetchedAt) : ICacheableRequest, IRequest> { public CacheConfiguration GetCacheConfiguration() => diff --git a/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQueryHandler.cs b/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQueryHandler.cs new file mode 100644 index 0000000..8abfc09 --- /dev/null +++ b/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountriesStatisticsQueryHandler.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Covid19Api.Presentation.Response; +using Covid19Api.Repositories.Abstractions; +using Covid19Api.Services.Abstractions.Calculators; +using Covid19Api.UseCases.Abstractions.Queries.CountryStatistics; +using MediatR; + +namespace Covid19Api.UseCases.Queries.CountryStatistics +{ + public class CalculateVaryForCountriesStatisticsQueryHandler : IRequestHandler> + { + private readonly ICountryStatisticsReadRepository countryStatisticsReadRepository; + private readonly ICountryVaryStatisticsCalculator countryVaryStatisticsCalculator; + + public CalculateVaryForCountriesStatisticsQueryHandler(ICountryStatisticsReadRepository countryStatisticsReadRepository, ICountryVaryStatisticsCalculator countryVaryStatisticsCalculator) + { + this.countryStatisticsReadRepository = countryStatisticsReadRepository; + this.countryVaryStatisticsCalculator = countryVaryStatisticsCalculator; + } + + public async Task> Handle(CalculateVaryForCountriesStatisticsQuery request, CancellationToken cancellationToken) + { + var historicalCountriesStatistics = await this.countryStatisticsReadRepository.HistoricalAsync(request.MinFetchedAt); + + return countryVaryStatisticsCalculator.Calculate(historicalCountriesStatistics); + } + } +} \ No newline at end of file diff --git a/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQueryHandler.cs b/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQueryHandler.cs new file mode 100644 index 0000000..cf96f2d --- /dev/null +++ b/src/Covid19Api.UseCases/Queries/CountryStatistics/CalculateVaryForCountryStatisticsQueryHandler.cs @@ -0,0 +1,30 @@ +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Covid19Api.Presentation.Response; +using Covid19Api.Repositories.Abstractions; +using Covid19Api.Services.Abstractions.Calculators; +using Covid19Api.UseCases.Abstractions.Queries.CountryStatistics; +using MediatR; + +namespace Covid19Api.UseCases.Queries.CountryStatistics +{ + public class CalculateVaryForCountryStatisticsQueryHandler : IRequestHandler> + { + private readonly ICountryStatisticsReadRepository countryStatisticsReadRepository; + private readonly ICountryVaryStatisticsCalculator countryVaryStatisticsCalculator; + + public CalculateVaryForCountryStatisticsQueryHandler(ICountryStatisticsReadRepository countryStatisticsReadRepository, ICountryVaryStatisticsCalculator countryVaryStatisticsCalculator) + { + this.countryStatisticsReadRepository = countryStatisticsReadRepository; + this.countryVaryStatisticsCalculator = countryVaryStatisticsCalculator; + } + + public async Task> Handle(CalculateVaryForCountryStatisticsQuery request, CancellationToken cancellationToken) + { + var historicalCountriesStatistics = await this.countryStatisticsReadRepository.HistoricalAsync(request.MinFetchedAt, request.Country); + + return this.countryVaryStatisticsCalculator.Calculate(historicalCountriesStatistics); + } + } +} \ No newline at end of file diff --git a/src/Covid19Api.UseCases/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQueryHandler.cs b/src/Covid19Api.UseCases/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQueryHandler.cs index aa65791..da1caea 100644 --- a/src/Covid19Api.UseCases/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQueryHandler.cs +++ b/src/Covid19Api.UseCases/Queries/CountryStatistics/LoadHistoricalCountryStatisticsForCountryQueryHandler.cs @@ -29,9 +29,7 @@ public async Task> Handle( LoadHistoricalCountryStatisticsForCountryQuery request, CancellationToken cancellationToken) { - var minFetchedAt = DateTime.UtcNow.Date.AddDays(-9); - - var statsForCountry = await this.countryStatisticsReadRepository.HistoricalAsync(minFetchedAt, request.Country); + var statsForCountry = await this.countryStatisticsReadRepository.HistoricalAsync(request.MinFetchedAt, request.Country); return this.mapper.Map>(statsForCountry); } diff --git a/test/Covid19Api.Services.Tests/CountryVaryStatisticsCalculatorTests.cs b/test/Covid19Api.Services.Tests/CountryVaryStatisticsCalculatorTests.cs new file mode 100644 index 0000000..c446ee0 --- /dev/null +++ b/test/Covid19Api.Services.Tests/CountryVaryStatisticsCalculatorTests.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Covid19Api.Domain; +using Covid19Api.Presentation.Response; +using Covid19Api.Services.Calculators; +using FluentAssertions; +using Xunit; + +namespace Covid19Api.Services.Tests +{ + public class CountryVaryStatisticsCalculatorTests + { + [Fact] + public void VaryCalculationForSixValuesWithinTwoDays() + { + var statistics = GivenSixCountryStatisticsSplitIntoTwoDays(); + var res = WhenCalculatingVary(statistics); + ThenCalculationShouldYieldExpectedValues(res); + } + + private static IEnumerable GivenSixCountryStatisticsSplitIntoTwoDays() + { + var dayOne = DateTime.UtcNow.Date; + var dayTwo = dayOne.AddDays(-1); + var statistics = new List + { + new("Germany", "DE", 100, 10, 10, 1, 50, 50, dayOne), + new("Italy", "IT", 100, 10, 10, 1, 50, 50, dayOne), + new("France", "FR", 100, 10, 10, 1, 50, 50, dayOne), + + new("SomeCountry", "DE", 150, 5, 40, 2, 25, 75, dayTwo), + new("SomeNotItaly", "IT", 150, 5, 40, 2, 25, 75, dayTwo), + new("SomeMaybeFrance", "FR", 150, 5, 40, 2, 25, 75, dayTwo), + }; + return statistics; + } + + private static List WhenCalculatingVary( + IEnumerable statistics) + { + var calculator = new CountryVaryStatisticsCalculator(); + var res = calculator.Calculate(statistics).ToList(); + return res; + } + + private static void ThenCalculationShouldYieldExpectedValues( + IReadOnlyList res) + { + res.Count.Should().Be(2); + var varyFirst = res[0].Vary.ToList(); + varyFirst.Count.Should().Be(6); + var varySecond = res[1].Vary.ToList(); + varySecond.Count.Should().Be(6); + } + } +} \ No newline at end of file diff --git a/test/Covid19Api.Services.Tests/Covid19Api.Services.Tests.csproj b/test/Covid19Api.Services.Tests/Covid19Api.Services.Tests.csproj new file mode 100644 index 0000000..5fe7c1c --- /dev/null +++ b/test/Covid19Api.Services.Tests/Covid19Api.Services.Tests.csproj @@ -0,0 +1,31 @@ + + + + net5.0 + + false + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + +