Skip to content

Commit

Permalink
Refactor & change long, lat data type to double
Browse files Browse the repository at this point in the history
  • Loading branch information
Gramli committed Feb 28, 2024
1 parent 9be910e commit f984730
Show file tree
Hide file tree
Showing 13 changed files with 48 additions and 64 deletions.
8 changes: 4 additions & 4 deletions src/Tests/HttpDebug/debug-tests.http
Expand Up @@ -3,11 +3,11 @@
@host={{hostname}}:{{port}}

### get current weather request
GET https://{{host}}/weather/v1/current?latitude=1&longtitude=1
GET https://{{host}}/weather/v1/current?latitude=38.5&longtitude=-78.5
Content-Type: application/json

### get forecast weather request
GET https://{{host}}/weather/v1/forecast?latitude=1&longtitude=1
GET https://{{host}}/weather/v1/forecast?latitude=38.5&longtitude=-78.5
Content-Type: application/json

### get favorites weather request
Expand All @@ -20,7 +20,7 @@ Content-Type: application/json

{
"location": {
"latitude": 1,
"longitude": 1
"latitude": 38.5,
"longitude": -78.5
}
}
Expand Up @@ -9,9 +9,9 @@ namespace Weather.API.SystemTests
{
public class WeatherSystemTests
{
private readonly long latitude = 1;
private readonly long longtitude = 1;
private readonly string cityName = "Mumford";
private readonly double latitude = 38.5;
private readonly double longtitude = -78.5;
private readonly string cityName = "Stanley";

private readonly HttpClient _httpClient;

Expand Down Expand Up @@ -41,7 +41,7 @@ public async Task GetForecastWeather()
{
//Arrange
//Act
var response = await _httpClient.GetAsync("weather/v1/forecast?latitude=1&longtitude=1");
var response = await _httpClient.GetAsync($"weather/v1/forecast?latitude={latitude}&longtitude={longtitude}");

//Assert
response.EnsureSuccessStatusCode();
Expand Down
Expand Up @@ -28,14 +28,14 @@ public async Task GetCurrentWeather_Failed()
var location = new LocationDto { Latitude = 15, Longitude = 25 };
var failedMessage = "message";

_weatherbiClientMock.Setup(x=>x.GetCurrentWeather(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Fail(failedMessage));
_weatherbiClientMock.Setup(x=>x.GetCurrentWeather(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Fail(failedMessage));
//Act
var result = await _uut.GetCurrentWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Equal(failedMessage, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<long>(y=>y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<double>(y=>y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -44,14 +44,14 @@ public async Task GetCurrentWeather_NullData()
//Arrange
var location = new LocationDto { Latitude = 15, Longitude = 25 };

_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok((CurrentWeatherDataDto)null));
_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok((CurrentWeatherDataDto)null));

Check warning on line 47 in src/Tests/UnitTests/Weather.Infrastructure.UnitTests/Services/WeatherServiceTests.cs

View workflow job for this annotation

GitHub Actions / Build & Unit Test

Converting null literal or possible null value to non-nullable type.

Check warning on line 47 in src/Tests/UnitTests/Weather.Infrastructure.UnitTests/Services/WeatherServiceTests.cs

View workflow job for this annotation

GitHub Actions / Build & Unit Test

Argument of type 'Result<CurrentWeatherDataDto?>' cannot be used for parameter 'value' of type 'Result<CurrentWeatherDataDto>' in 'IReturnsResult<IWeatherbitHttpClient> ReturnsExtensions.ReturnsAsync<IWeatherbitHttpClient, Result<CurrentWeatherDataDto>>(IReturns<IWeatherbitHttpClient, Task<Result<CurrentWeatherDataDto>>> mock, Result<CurrentWeatherDataDto> value)' due to differences in the nullability of reference types.
//Act
var result = await _uut.GetCurrentWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Equal(ErrorMessages.ExternalClientGetDataFailed_EmptyOrNull, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -60,14 +60,14 @@ public async Task GetCurrentWeather_EmptyData()
//Arrange
var location = new LocationDto { Latitude = 15, Longitude = 25 };

_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto()));
_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto()));
//Act
var result = await _uut.GetCurrentWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Contains(ErrorMessages.ExternalClientGetDataFailed_EmptyOrNull, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -81,7 +81,7 @@ public async Task GetCurrentWeather_ManyData()
new Wheaterbit.Client.Dtos.CurrentWeatherDto()
};

_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto
_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto
{
Data = data
}));
Expand All @@ -91,7 +91,7 @@ public async Task GetCurrentWeather_ManyData()
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Contains(string.Format(ErrorMessages.ExternalClientGetDataFailed_CorruptedData_InvalidCount, 2), result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -106,7 +106,7 @@ public async Task GetCurrentWeather_Success()

var mapResult = new Domain.Dtos.CurrentWeatherDto();

_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto
_weatherbiClientMock.Setup(x => x.GetCurrentWeather(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new CurrentWeatherDataDto
{
Data = data
}));
Expand All @@ -119,7 +119,7 @@ public async Task GetCurrentWeather_Success()
//Assert
Assert.True(result.IsSuccess);
Assert.Empty(result.Errors);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetCurrentWeather(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
Assert.Equivalent(mapResult, result.Value);
_mapperMock.Verify(x => x.Map<Domain.Dtos.CurrentWeatherDto>(It.IsAny<Wheaterbit.Client.Dtos.CurrentWeatherDto>()), Times.Once);
}
Expand All @@ -131,14 +131,14 @@ public async Task GetForecastWeather_Failed()
var location = new LocationDto { Latitude = 15, Longitude = 25 };
var failedMessage = "message";

_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Fail(failedMessage));
_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Fail(failedMessage));
//Act
var result = await _uut.GetForecastWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Equal(failedMessage, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -147,14 +147,14 @@ public async Task GetForecastWeather_NullData()
//Arrange
var location = new LocationDto { Latitude = 15, Longitude = 25 };

_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok((Wheaterbit.Client.Dtos.ForecastWeatherDto)null));
_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok((Wheaterbit.Client.Dtos.ForecastWeatherDto)null));
//Act
var result = await _uut.GetForecastWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Equal(ErrorMessages.ExternalClientGetDataFailed_EmptyOrNull, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -163,14 +163,14 @@ public async Task GetForecastWeather_EmptyData()
//Arrange
var location = new LocationDto { Latitude = 15, Longitude = 25 };

_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new Wheaterbit.Client.Dtos.ForecastWeatherDto()));
_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(new Wheaterbit.Client.Dtos.ForecastWeatherDto()));
//Act
var result = await _uut.GetForecastWeather(location, CancellationToken.None);
//Assert
Assert.True(result.IsFailed);
Assert.Single(result.Errors);
Assert.Contains(ErrorMessages.ExternalClientGetDataFailed_EmptyOrNull, result.Errors.First().Message);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
}

[Fact]
Expand All @@ -188,7 +188,7 @@ public async Task GetForecastWeather_Success()

var mapResult = new Domain.Dtos.ForecastWeatherDto();

_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<long>(), It.IsAny<long>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(data));
_weatherbiClientMock.Setup(x => x.GetSixteenDayForecast(It.IsAny<double>(), It.IsAny<double>(), It.IsAny<CancellationToken>())).ReturnsAsync(Result.Ok(data));

_mapperMock.Setup(x => x.Map<Domain.Dtos.ForecastWeatherDto>(It.IsAny<Wheaterbit.Client.Dtos.ForecastWeatherDto>())).Returns(mapResult);

Expand All @@ -198,7 +198,7 @@ public async Task GetForecastWeather_Success()
//Assert
Assert.True(result.IsSuccess);
Assert.Empty(result.Errors);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<long>(y => y.Equals(location.Latitude)), It.Is<long>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
_weatherbiClientMock.Verify(x => x.GetSixteenDayForecast(It.Is<double>(y => y.Equals(location.Latitude)), It.Is<double>(y => y.Equals(location.Longitude)), It.IsAny<CancellationToken>()), Times.Once);
Assert.Equivalent(mapResult, result.Value);
_mapperMock.Verify(x => x.Map<Domain.Dtos.ForecastWeatherDto>(It.IsAny<Wheaterbit.Client.Dtos.ForecastWeatherDto>()), Times.Once);
}
Expand Down
4 changes: 2 additions & 2 deletions src/Weather.API/EndpointBuilders/WeatherBuilder.cs
Expand Up @@ -25,7 +25,7 @@ public static IEndpointRouteBuilder BuildWeatherEndpoints(this IEndpointRouteBui
private static IEndpointRouteBuilder BuildActualWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
{
endpointRouteBuilder.MapGet("v1/current",
async (long latitude, long longtitude, [FromServices] IGetCurrentWeatherHandler handler, CancellationToken cancellationToken) =>
async (double latitude, double longtitude, [FromServices] IGetCurrentWeatherHandler handler, CancellationToken cancellationToken) =>
await handler.SendAsync(new GetCurrentWeatherQuery(latitude,longtitude), cancellationToken))
.Produces<DataResponse<CurrentWeatherDto>>()
.WithName("GetCurrentWeather")
Expand All @@ -36,7 +36,7 @@ await handler.SendAsync(new GetCurrentWeatherQuery(latitude,longtitude), cancell
private static IEndpointRouteBuilder BuildForecastWeatherEndpoints(this IEndpointRouteBuilder endpointRouteBuilder)
{
endpointRouteBuilder.MapGet("v1/forecast",
async (long latitude, long longtitude, [FromServices] IGetForecastWeatherHandler handler, CancellationToken cancellationToken) =>
async (double latitude, double longtitude, [FromServices] IGetForecastWeatherHandler handler, CancellationToken cancellationToken) =>
await handler.SendAsync(new GetForecastWeatherQuery(latitude, longtitude), cancellationToken))
.Produces<DataResponse<ForecastWeatherDto>>()
.WithName("GetForecastWeather")
Expand Down
Expand Up @@ -15,30 +15,24 @@ namespace Weather.Core.Configuration
public static class ContainerConfigurationExtension
{
public static IServiceCollection AddCore(this IServiceCollection serviceCollection)
{
return serviceCollection
=> serviceCollection
.AddValidation()
.AddHandlers();
}

private static IServiceCollection AddHandlers(this IServiceCollection serviceCollection)
{
return serviceCollection
=> serviceCollection
.AddScoped<IGetCurrentWeatherHandler, GetCurrentWeatherHandler>()
.AddScoped<IGetFavoritesHandler, GetFavoritesHandler>()
.AddScoped<IGetForecastWeatherHandler, GetForecastWeatherHandler>()
.AddScoped<IAddFavoriteHandler, AddFavoriteHandler>();
}

private static IServiceCollection AddValidation(this IServiceCollection serviceCollection)
{
return serviceCollection
=> serviceCollection
.AddValidotSingleton<IValidator<CurrentWeatherDto>, CurrentWeatherDtoSpecificationHolder, CurrentWeatherDto>()
.AddValidotSingleton<IValidator<ForecastWeatherDto>, ForecastWeatherDtoSpecificationHolder, ForecastWeatherDto>()
.AddValidotSingleton<IValidator<LocationDto>, LocationDtoSpecificationHolder, LocationDto>()
.AddValidotSingleton<IValidator<AddFavoriteCommand>, AddFavoriteCommandSpecificationHolder, AddFavoriteCommand>()
.AddValidotSingleton<IValidator<GetCurrentWeatherQuery>, GetCurrentWeatherQuerySpecificationHolder, GetCurrentWeatherQuery>()
.AddValidotSingleton<IValidator<GetForecastWeatherQuery>, GetForecastWeatherSpecificationHolder, GetForecastWeatherQuery>();
}
}
}
4 changes: 2 additions & 2 deletions src/Weather.Core/Validation/GeneralPredicates.cs
Expand Up @@ -6,8 +6,8 @@ namespace Weather.Core.Validation
internal static class GeneralPredicates
{
internal static readonly Predicate<double> isValidTemperature = m => m < 60 && m > -90;
internal static readonly Predicate<long> isValidLatitude = m => m >= -90 && m <= 90;
internal static readonly Predicate<long> isValidLongtitude = m => m >= -180 && m <= 180;
internal static readonly Predicate<double> isValidLatitude = m => m >= -90 && m <= 90;
internal static readonly Predicate<double> isValidLongtitude = m => m >= -180 && m <= 180;
internal static readonly Specification<LocationDto> isValidLocation = s => s
.Member(m => m.Latitude, m => m.Rule(isValidLatitude))
.Member(m => m.Longitude, m => m.Rule(isValidLongtitude));
Expand Down
4 changes: 2 additions & 2 deletions src/Weather.Domain/Dtos/LocationDto.cs
Expand Up @@ -2,7 +2,7 @@
{
public sealed class LocationDto
{
public long Latitude { get; init; }
public long Longitude { get; init; }
public double Latitude { get; init; }
public double Longitude { get; init; }
}
}
2 changes: 1 addition & 1 deletion src/Weather.Domain/Queries/GetCurrentWeatherQuery.cs
Expand Up @@ -5,7 +5,7 @@ namespace Weather.Domain.Queries
public sealed class GetCurrentWeatherQuery
{
public LocationDto Location { get; init; }
public GetCurrentWeatherQuery(long latitude, long longtitude)
public GetCurrentWeatherQuery(double latitude, double longtitude)
{
Location = new LocationDto
{
Expand Down
2 changes: 1 addition & 1 deletion src/Weather.Domain/Queries/GetForecastWeatherQuery.cs
Expand Up @@ -5,7 +5,7 @@ namespace Weather.Domain.Queries
public sealed class GetForecastWeatherQuery
{
public LocationDto Location { get; init; }
public GetForecastWeatherQuery(long latitude, long longtitude)
public GetForecastWeatherQuery(double latitude, double longtitude)
{
Location = new LocationDto
{
Expand Down

0 comments on commit f984730

Please sign in to comment.