diff --git a/README.md b/README.md index 6d4cb82..3ffa83f 100644 --- a/README.md +++ b/README.md @@ -5,11 +5,11 @@ Java API for OpenWeatherMap services. Free: * Current weather data * 5 day / 3-hour forecast +* One Call API ### Will be implemented later: Free: -* One Call API * Air pollution * Geocoding API * Weather Stations @@ -26,14 +26,14 @@ Paid: com.github.prominence openweathermap-api - 2.0.1 + 2.1.0 ``` ### Gradle coordinates: ```groovy -compile('com.github.prominence:openweathermap-api:2.0.1') +compile('com.github.prominence:openweathermap-api:2.1.0') ``` ### Documentation @@ -42,6 +42,7 @@ compile('com.github.prominence:openweathermap-api:2.0.1') * [OpenWeatherMap Java API - 1.2](docs/Release_1.2.md) * [OpenWeatherMap Java API - 2.0.0](docs/Release_2.0.0.md) * [OpenWeatherMap Java API - 2.0.1](docs/Release_2.0.1.md) +* [OpenWeatherMap Java API - 2.1.0](docs/Release_2.1.0.md) * [OpenWeatherMap Java API - SNAPSHOT](docs/SNAPSHOT.md) ### License diff --git a/docs/Release_2.0.0.md b/docs/Release_2.0.0.md index b08e2c6..491d13d 100644 --- a/docs/Release_2.0.0.md +++ b/docs/Release_2.0.0.md @@ -79,7 +79,7 @@ final Weather weather = openWeatherClient final List weatherList = openWeatherClient .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() diff --git a/docs/Release_2.0.1.md b/docs/Release_2.0.1.md index fdf3c0b..2858a11 100644 --- a/docs/Release_2.0.1.md +++ b/docs/Release_2.0.1.md @@ -79,7 +79,7 @@ final Weather weather = openWeatherClient final List weatherList = openWeatherClient .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() diff --git a/docs/Release_2.1.0.md b/docs/Release_2.1.0.md new file mode 100644 index 0000000..b20ea78 --- /dev/null +++ b/docs/Release_2.1.0.md @@ -0,0 +1,484 @@ +### Implemented features: +* Current weather data +* 5 day / 3-hour forecast +* One Call API + +### Maven coordinates: + +```xml + + com.github.prominence + openweathermap-api + 2.1.0 + +``` + +### Gradle coordinates: + +```groovy +compile('com.github.prominence:openweathermap-api:2.1.0') +``` + +### How to use: + +Firstly, you need to create the instance of `OpenWeatherMapClient` class: +```java +OpenWeatherMapClient openWeatherClient = new OpenWeatherMapClient(API_TOKEN); +``` +where `API_TOKEN` is your token([you can get it here](https://home.openweathermap.org/api_keys)) as `String`. + +Currently, available APIs are: +* `currentWeather()` +* `forecast5Day3HourStep()` +* `oneCall()` + +Default(more or less) customization points: +```java +... +// response language +.language(Language.RUSSIAN) +... +// response units of measure +.unitSystem(UnitSystem.IMPERIAL) +... +``` + +Available output forms: +* `asJava()` +* `asJSON()` + +Additional output forms, available for several APIs: +* `asXML()` +* `asHTML()` + +_All response forms can be in **sync** and **async** variants._ + +#### Current weather data +Examples: +```java +final String weatherJson = openWeatherClient + .currentWeather() + .single() + .byCityName("Minsk") + .language(Language.RUSSIAN) + .unitSystem(UnitSystem.IMPERIAL) + .retrieve() + .asJSON(); +``` + +```java +final Weather weather = openWeatherClient + .currentWeather() + .single() + .byCityName("Minsk") + .language(Language.RUSSIAN) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); +``` + +```java +final List weatherList = openWeatherClient + .currentWeather() + .multiple() + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) + .language(Language.GERMAN) + .unitSystem(UnitSystem.IMPERIAL) + .retrieve() + .asJava(); +``` + +```java +final CompletableFuture weatherXmlFuture = openWeatherClient + .currentWeather() + .single() + .byZipCodeAndCountry("220015", "by") + .language(Language.RUSSIAN) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asXML(); +``` + +You are able to set preferable options(via chain methods) and execute appropriate request. + +`com.github.prominence.openweathermap.api.model.weather.Weather`'s useful public methods(setters are not listed): + +| Method | Description | +|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `getCalculationTime()` | Returns `LocalDateTime` object with data calculation time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. | +| `getAtmosphericPressure()`| Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. | +| `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. | +| `getWind()` | Returns `Wind` instance that contains wind information: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` instance that contains information about rain volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. | +| `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last one hour and/or the last 3 hours. Can be absent in case of no data. | +| `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. | +| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset` and `coordinate`. | +| `toString()` | Returns informative string for the whole available weather information. | + +`toString()` output example: +``` +Location: Minsk(BY), Weather: clear sky, -4.22 ℃, 1020.0 hPa, Clouds: 0% +``` + +#### 5 day / 3-hour forecast +Examples: +```java +final Forecast forecast = openWeatherClient + .forecast5Day3HourStep() + .byCityName("Minsk") + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .count(15) + .retrieve() + .asJava(); +``` + +```java +final String forecastJson = getClient() + .forecast5Day3HourStep() + .byCityName("New York", "NY", "US") + .language(Language.SPANISH) + .unitSystem(UnitSystem.IMPERIAL) + .count(15) + .retrieve() + .asJSON(); +``` + +```java +CompletableFuture forecastFuture = getClient() + .forecast5Day3HourStep() + .byCityId(350001514) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .count(15) + .retrieveAsync() + .asXML(); +``` + +```java +final String forecastXml = getClient() + .forecast5Day3HourStep() + .byZipCodeInUSA("10005") + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asXML(); +``` + +You are able to set preferable options(via chain methods) and execute appropriate request. + +`com.github.prominence.openweathermap.api.model.forecast.free.Forecast`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| +| `getLocation()` | Returns `Location` object. Available fields: `id`, `name`, `countryCode`, `sunrise` and `sunset` time, `zoneOffset`, `coordinate` and `population`. | +| `getWeatherForecasts()` | Returns list of `WeatherForecast` objects with forecast information. | +| `toString()` | Returns informative string for the whole available forecast information. | + +`toString()` output example: +``` +A forecast for Minsk with 15 timestamps. +``` + +`com.github.prominence.openweathermap.api.model.forecast.WeatherForecast`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. | +| `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. | +| `getWind()` | Returns `Wind` instance that contains wind information: `speed`, `degrees` and `unit`. | +| `getRain()` | Returns `Rain` instance that contains information about rain volume for the last 3 hours. Can be absent in case of no data. | +| `getSnow()` | Returns `Snow` instance that contains information about snow volume for the last 3 hours. Can be absent in case of no data. | +| `getClouds()` | Returns `Clouds` instance that contains information about cloudiness percentage. | +| `getForecastTimeISO()` | Returns String with time of data forecasted, ISO, UTC. | +| `getDayTime()` | Returns enumerations representing the part of day(day, night). | +| `toString()` | Returns informative string for the forecast of particular timestamp. | + +#### One Call API +Examples: +```java +final CurrentWeatherData currentWeatherData = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); +``` + +```java +final CurrentWeatherData currentWeatherData = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY) + .retrieve() + .asJava(); +``` + +```java +final CompletableFuture currentWeatherDataFuture = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); +``` + +```java +final String responseJson = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); +``` + +```java +final HistoricalWeatherData historicalWeatherData = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); +``` + +```java +final String responseJson = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); +``` + +```java +final CompletableFuture historicalWeatherDataFuture = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); +``` + +```java +final CompletableFuture responseJsonFuture = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJSON(); +``` + +You are able to set preferable options(via chain methods) and execute appropriate request. + +`com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|--------------------------------------------------------------------------------| +| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | +| `getTimezone()` | Returns location timezone object. | +| `getTimezoneOffset()` | Returns zone offset. | +| `getCurrent()` | Returns `Current` object with current weather state if available. | +| `getMinutelyList()` | Returns list of `Minutely` objects if available. | +| `getHourlyList()` | Returns list of `Houlry` objects if available. | +| `getDailyList()` | Returns list of `Daily` objects if available. | +| `getAlerts()` | Returns list of `Alert` objects if available. | + +`com.github.prominence.openweathermap.api.model.onecall.Current`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Minutely`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|---------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getPrecipitationVolume()` | Returns precipitation volume. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Hourly`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Daily`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `DailyTemperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). | +| `getRain()` | Returns `DailyRain` object. Available fields: `value`. | +| `getSnow()` | Returns `DailySnow` object. Available fields: `value`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Alert`'s useful public methods(setters are not listed): + +| Method | Description | +|------------------------------|--------------------------------------------------------| +| `getSenderName()` | Returns alert sender name. | +| `getEventName()` | Returns alert event name. | +| `getStartTime()` | Returns `LocalDateTime` when event should start. | +| `getEndTime()` | Returns `LocalDateTime` when event should end. | +| `getDescription()` | Returns alert description. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------| +| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | +| `getTimezone()` | Returns location timezone object. | +| `getTimezoneOffset()` | Returns zone offset. | +| `getHistoricalWeather()` | Returns `HistoricalWeather` object with historical weather state. | +| `getHourlyList()` | Returns list of `HourlyHistorical` objects. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +### Constants and options + +#### Language +| Constant | Description | +|-----------------------------------|-------------------------------| +| Language.AFRIKAANS | Afrikaans language. | +| Language.ALBANIAN | ALBANIAN language. | +| Language.ARABIC | Arabic language. | +| Language.AZERBAIJANI | Azerbaijani language. | +| Language.BULGARIAN | Bulgarian language. | +| Language.CATALAN | Catalan language. | +| Language.CZECH | Czech language. | +| Language.DANISH | Danish language. | +| Language.GERMAN | German language. | +| Language.GREEK | Greek language. | +| Language.ENGLISH | English language. | +| Language.BASQUE | Basque language. | +| Language.PERSIAN | Persian (Farsi) language. | +| Language.FINNISH | Finnish language. | +| Language.FRENCH | French language. | +| Language.GALICIAN | Galician language. | +| Language.HEBREW | Hebrew language. | +| Language.HINDI | Hindi language. | +| Language.CROATIAN | Croatian language. | +| Language.HUNGARIAN | Hungarian language. | +| Language.INDONESIAN | Indonesian language. | +| Language.ITALIAN | Italian language. | +| Language.JAPANESE | Japanese language. | +| Language.KOREAN | Korean language. | +| Language.LATVIAN | Latvian language. | +| Language.LITHUANIAN | Lithuanian language. | +| Language.MACEDONIAN | Macedonian language. | +| Language.NORWEGIAN | Norwegian language. | +| Language.DUTCH | Dutch language. | +| Language.POLISH | Polish language. | +| Language.PORTUGUESE | Portuguese language. | +| Language.PORTUGUES_BRAZIL | Português Brasil language. | +| Language.ROMANIAN | Romanian language. | +| Language.RUSSIAN | Russian language. | +| Language.SWEDISH | Swedish language. | +| Language.SLOVAK | Slovak language. | +| Language.SLOVENIAN | Slovenian language. | +| Language.SPANISH | Spanish language. | +| Language.SERBIAN | Serbian language. | +| Language.THAI | Thai language. | +| Language.TURKISH | Turkish language. | +| Language.UKRANIAN | Ukrainian language. | +| Language.VIETNAMESE | Vietnamese language. | +| Language.CHINESE_SIMPLIFIED | Chinese Simplified language. | +| Language.CHINESE_TRADITIONAL | Chinese Traditional language. | +| Language.ZULU | Zulu language. | + +#### Unit +| Constant | Description | +|----------------------|------------------------------------------------| +| Unit.METRIC_SYSTEM | Celsius, meter/sec, hPa, mm(rain, snow). | +| Unit.IMPERIAL_SYSTEM | Fahrenheit, miles/hour, hPa, mm(rain, snow). | +| Unit.STANDARD_SYSTEM | Kelvin, meter/sec, hPa, mm(rain, snow). | + +### Dependencies +* com.fasterxml.jackson.core:jackson-databind:2.12.2 +* org.slf4j:slf4j-api:1.7.30 (*compile*) +* org.junit.jupiter:junit-jupiter-engine:5.7.1 (*test*) +* org.junit.platform:junit-platform-runner:1.7.1 (*test*) \ No newline at end of file diff --git a/docs/SNAPSHOT.md b/docs/SNAPSHOT.md index a9fabea..b20ea78 100644 --- a/docs/SNAPSHOT.md +++ b/docs/SNAPSHOT.md @@ -1,6 +1,7 @@ ### Implemented features: * Current weather data * 5 day / 3-hour forecast +* One Call API ### Maven coordinates: @@ -8,14 +9,14 @@ com.github.prominence openweathermap-api - 2.0.1-SNAPSHOT + 2.1.0 ``` ### Gradle coordinates: ```groovy -compile('com.github.prominence:openweathermap-api:2.0.1-SNAPSHOT') +compile('com.github.prominence:openweathermap-api:2.1.0') ``` ### How to use: @@ -29,6 +30,7 @@ where `API_TOKEN` is your token([you can get it here](https://home.openweatherma Currently, available APIs are: * `currentWeather()` * `forecast5Day3HourStep()` +* `oneCall()` Default(more or less) customization points: ```java @@ -79,7 +81,7 @@ final Weather weather = openWeatherClient final List weatherList = openWeatherClient .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() @@ -103,11 +105,8 @@ You are able to set preferable options(via chain methods) and execute appropriat | Method | Description | |---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `getState()` | Returns short weather description. Example: `Clear`. | -| `getDescription()` | Returns weather description. Example: `clear sky`. | -| `getWeatherIconId()` | Returns a weather state ID. Examples: `01d`, `01n`, `11n`, etc. | -| `getWeatherIconUrl()` | Returns a link to weather icon hosted on https://openweathermap.org website. | -| `getCalculatedOn()` | Returns `LocalDateTime` object with data calculation time. | +| `getCalculationTime()` | Returns `LocalDateTime` object with data calculation time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | | `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. | | `getAtmosphericPressure()`| Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. | | `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. | @@ -170,7 +169,7 @@ final String forecastXml = getClient() You are able to set preferable options(via chain methods) and execute appropriate request. -`com.github.prominence.openweathermap.api.request.forecast.free.Forecast`'s useful public methods(setters are not listed): +`com.github.prominence.openweathermap.api.model.forecast.free.Forecast`'s useful public methods(setters are not listed): | Method | Description | |-------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------| @@ -187,11 +186,8 @@ A forecast for Minsk with 15 timestamps. | Method | Description | |-------------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `getState()` | Returns short weather description. Example: `Clear`. | -| `getDescription()` | Returns weather description. Example: `clear sky`. | -| `getWeatherIconId()` | Returns a weather state ID. Examples: `01d`, `01n`, `11n`, etc. | -| `getWeatherIconUrl()` | Returns a link to weather icon hosted on https://openweathermap.org website. | | `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | | `getTemperature()` | Returns `Temperature` instance that contains information about temperature. Available fields: `value`, `maxTemperature`, `minTemperature`, `feelsLike` and `unit`. | | `getAtmosphericPressure()` | Returns `AtmosphericPressure` instance that contains information about atmospheric pressure. Available fields: `value`, `seaLevelValue`, `groundLevelValue` and `unit`. | | `getHumidity()` | Returns `Humidity` instance that contains humidity percentage information. | @@ -203,44 +199,276 @@ A forecast for Minsk with 15 timestamps. | `getDayTime()` | Returns enumerations representing the part of day(day, night). | | `toString()` | Returns informative string for the forecast of particular timestamp. | +#### One Call API +Examples: +```java +final CurrentWeatherData currentWeatherData = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); +``` + +```java +final CurrentWeatherData currentWeatherData = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY) + .retrieve() + .asJava(); +``` + +```java +final CompletableFuture currentWeatherDataFuture = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); +``` + +```java +final String responseJson = openWeatherClient + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); +``` + +```java +final HistoricalWeatherData historicalWeatherData = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); +``` + +```java +final String responseJson = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); +``` + +```java +final CompletableFuture historicalWeatherDataFuture = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); +``` + +```java +final CompletableFuture responseJsonFuture = openWeatherClient + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJSON(); +``` + +You are able to set preferable options(via chain methods) and execute appropriate request. + +`com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|--------------------------------------------------------------------------------| +| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | +| `getTimezone()` | Returns location timezone object. | +| `getTimezoneOffset()` | Returns zone offset. | +| `getCurrent()` | Returns `Current` object with current weather state if available. | +| `getMinutelyList()` | Returns list of `Minutely` objects if available. | +| `getHourlyList()` | Returns list of `Houlry` objects if available. | +| `getDailyList()` | Returns list of `Daily` objects if available. | +| `getAlerts()` | Returns list of `Alert` objects if available. | + +`com.github.prominence.openweathermap.api.model.onecall.Current`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Minutely`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|---------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getPrecipitationVolume()` | Returns precipitation volume. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Hourly`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Daily`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `DailyTemperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getProbabilityOfPrecipitation()` | Returns probability of precipitation(not percentage). | +| `getRain()` | Returns `DailyRain` object. Available fields: `value`. | +| `getSnow()` | Returns `DailySnow` object. Available fields: `value`. | + +`com.github.prominence.openweathermap.api.model.onecall.current.Alert`'s useful public methods(setters are not listed): + +| Method | Description | +|------------------------------|--------------------------------------------------------| +| `getSenderName()` | Returns alert sender name. | +| `getEventName()` | Returns alert event name. | +| `getStartTime()` | Returns `LocalDateTime` when event should start. | +| `getEndTime()` | Returns `LocalDateTime` when event should end. | +| `getDescription()` | Returns alert description. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------| +| `getCoordinate()` | Returns `Coordinate` object. Available fields: `latitude`, `longitude`. | +| `getTimezone()` | Returns location timezone object. | +| `getTimezoneOffset()` | Returns zone offset. | +| `getHistoricalWeather()` | Returns `HistoricalWeather` object with historical weather state. | +| `getHourlyList()` | Returns list of `HourlyHistorical` objects. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather`'s useful public methods(setters are not listed): + +| Method | Description | +|-------------------------------|-------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getSunriseTime()` | Returns `LocalDateTime` object with sunrise time. | +| `getSunsetTime()` | Returns `LocalDateTime` object with sunset time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getUvIndex()` | Returns UV index value. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + +`com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical`'s useful public methods(setters are not listed): + +| Method | Description | +|-----------------------------------|---------------------------------------------------------------------------------------------------| +| `getForecastTime()` | Returns `LocalDateTime` object with weather forecast time. | +| `getWeatherState()` | Returns `WeatherState` object with basic weather state information. | +| `getTemperature()` | Returns `Temperature` object. Available fields: `value`, `feelsLike`, `dewPoint` and `unit`. | +| `getAtmosphericPressure()` | Returns `AtmosphericPressure` object. Available fields: `seaLevelValue`. | +| `getHumidity()` | Returns `Humidity` object. Available fields: `value` and `unit`. | +| `getClouds()` | Returns `Clouds` object. Available fields: `value` and `unit`. | +| `getVisibilityInMetres()` | Returns visibility in metres. | +| `getWind()` | Returns `Wind` object. Available fields: `speed`, `degrees`, `gust` and `unit`. | +| `getRain()` | Returns `Rain` object. Available fields: `oneHourLevel` and `unit`. | +| `getSnow()` | Returns `Snow` object. Available fields: `oneHourLevel` and `unit`. | + ### Constants and options #### Language | Constant | Description | |-----------------------------------|-------------------------------| +| Language.AFRIKAANS | Afrikaans language. | +| Language.ALBANIAN | ALBANIAN language. | | Language.ARABIC | Arabic language. | +| Language.AZERBAIJANI | Azerbaijani language. | | Language.BULGARIAN | Bulgarian language. | | Language.CATALAN | Catalan language. | | Language.CZECH | Czech language. | +| Language.DANISH | Danish language. | | Language.GERMAN | German language. | | Language.GREEK | Greek language. | | Language.ENGLISH | English language. | +| Language.BASQUE | Basque language. | | Language.PERSIAN | Persian (Farsi) language. | | Language.FINNISH | Finnish language. | | Language.FRENCH | French language. | | Language.GALICIAN | Galician language. | +| Language.HEBREW | Hebrew language. | +| Language.HINDI | Hindi language. | | Language.CROATIAN | Croatian language. | | Language.HUNGARIAN | Hungarian language. | +| Language.INDONESIAN | Indonesian language. | | Language.ITALIAN | Italian language. | | Language.JAPANESE | Japanese language. | | Language.KOREAN | Korean language. | | Language.LATVIAN | Latvian language. | | Language.LITHUANIAN | Lithuanian language. | | Language.MACEDONIAN | Macedonian language. | +| Language.NORWEGIAN | Norwegian language. | | Language.DUTCH | Dutch language. | | Language.POLISH | Polish language. | | Language.PORTUGUESE | Portuguese language. | +| Language.PORTUGUES_BRAZIL | Português Brasil language. | | Language.ROMANIAN | Romanian language. | | Language.RUSSIAN | Russian language. | | Language.SWEDISH | Swedish language. | | Language.SLOVAK | Slovak language. | | Language.SLOVENIAN | Slovenian language. | | Language.SPANISH | Spanish language. | +| Language.SERBIAN | Serbian language. | +| Language.THAI | Thai language. | | Language.TURKISH | Turkish language. | | Language.UKRANIAN | Ukrainian language. | | Language.VIETNAMESE | Vietnamese language. | | Language.CHINESE_SIMPLIFIED | Chinese Simplified language. | | Language.CHINESE_TRADITIONAL | Chinese Traditional language. | +| Language.ZULU | Zulu language. | #### Unit | Constant | Description | @@ -252,4 +480,5 @@ A forecast for Minsk with 15 timestamps. ### Dependencies * com.fasterxml.jackson.core:jackson-databind:2.12.2 * org.slf4j:slf4j-api:1.7.30 (*compile*) -* junit:junit:4.13.1 (*test*) \ No newline at end of file +* org.junit.jupiter:junit-jupiter-engine:5.7.1 (*test*) +* org.junit.platform:junit-platform-runner:1.7.1 (*test*) \ No newline at end of file diff --git a/pom.xml b/pom.xml index 7ed6f76..8899dd6 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ com.github.prominence openweathermap-api - 2.0.1 + 2.1.0 jar Java OpenWeatherMap API @@ -27,7 +27,7 @@ MIT License - http://www.opensource.org/licenses/mit-license.php + https://www.opensource.org/licenses/mit-license.php repo @@ -150,6 +150,12 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + 2.22.2 + @@ -167,10 +173,15 @@ - junit - junit - 4.13.1 + org.junit.jupiter + junit-jupiter-engine + 5.7.1 test + + org.junit.platform + junit-platform-runner + 1.7.1 + \ No newline at end of file diff --git a/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java b/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java index e0d6440..5579c4a 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java +++ b/src/main/java/com/github/prominence/openweathermap/api/OpenWeatherMapClient.java @@ -25,6 +25,8 @@ package com.github.prominence.openweathermap.api; import com.github.prominence.openweathermap.api.annotation.SubscriptionAvailability; import com.github.prominence.openweathermap.api.request.forecast.free.FiveDayThreeHourStepForecastRequester; import com.github.prominence.openweathermap.api.request.forecast.free.FiveDayThreeHourStepForecastRequesterImpl; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherRequester; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherRequesterImpl; import com.github.prominence.openweathermap.api.request.weather.CurrentWeatherRequester; import com.github.prominence.openweathermap.api.request.weather.CurrentWeatherRequesterImpl; @@ -39,7 +41,7 @@ public class OpenWeatherMapClient { /** * Created OpenWeatherMap client object. - * @param apiKey API key obtained on OpwnWeatherMap site. + * @param apiKey API key obtained on OpenWeatherMap site. */ public OpenWeatherMapClient(String apiKey) { this.apiKey = apiKey; @@ -62,4 +64,14 @@ public class OpenWeatherMapClient { public FiveDayThreeHourStepForecastRequester forecast5Day3HourStep() { return new FiveDayThreeHourStepForecastRequesterImpl(apiKey); } + + /** + * One Call API. + * To get information about current weather, minute forecast for 1 hour, hourly forecast for 48 hours, daily forecast for 7 days and government weather alerts. + * @return requester for retrieving one call weather information. + */ + @SubscriptionAvailability(plans = ALL) + public OneCallWeatherRequester oneCall() { + return new OneCallWeatherRequesterImpl(apiKey); + } } diff --git a/src/main/java/com/github/prominence/openweathermap/api/enums/Language.java b/src/main/java/com/github/prominence/openweathermap/api/enums/Language.java index 869b9e7..47a82ba 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/enums/Language.java +++ b/src/main/java/com/github/prominence/openweathermap/api/enums/Language.java @@ -27,11 +27,26 @@ package com.github.prominence.openweathermap.api.enums; * Usually it could be specified to get response with some fields translated into desired language. */ public enum Language { + /** + * Afrikaans language. + */ + AFRIKAANS("af"), + + /** + * Albanian language. + */ + ALBANIAN("al"), + /** * Arabic language. */ ARABIC("ar"), + /** + * Azerbaijani language. + */ + AZERBAIJANI("az"), + /** * Bulgarian language. */ @@ -47,6 +62,11 @@ public enum Language { */ CZECH("cz"), + /** + * Danish language + */ + DANISH("da"), + /** * German language. */ @@ -62,6 +82,11 @@ public enum Language { */ ENGLISH("en"), + /** + * Basque language. + */ + BASQUE("eu"), + /** * Persian language. */ @@ -82,6 +107,16 @@ public enum Language { */ GALICIAN("gl"), + /** + * Hebrew language. + */ + HEBREW("he"), + + /** + * Hindi language. + */ + HINDI("hi"), + /** * Croatian language. */ @@ -92,6 +127,11 @@ public enum Language { */ HUNGARIAN("hu"), + /** + * Indonesian language. + */ + INDONESIAN("id"), + /** * Italian language. */ @@ -122,6 +162,11 @@ public enum Language { */ MACEDONIAN("mk"), + /** + * Norwegian language. + */ + NORWEGIAN("no"), + /** * Dutch language. */ @@ -137,6 +182,11 @@ public enum Language { */ PORTUGUESE("pt"), + /** + * Português Brasil language. + */ + PORTUGUES_BRAZIL("pt_br"), + /** * Romanian language. */ @@ -165,7 +215,17 @@ public enum Language { /** * Spanish language. */ - SPANISH("en"), + SPANISH("es"), + + /** + * Serbian language. + */ + SERBIAN("sr"), + + /** + * Thai language. + */ + THAI("th"), /** * Turkish language. @@ -190,7 +250,12 @@ public enum Language { /** * Chinese traditional language. */ - CHINESE_TRADITIONAL("zh_tw"); + CHINESE_TRADITIONAL("zh_tw"), + + /** + * Zulu language. + */ + ZULU("zu"); private final String value; diff --git a/src/main/java/com/github/prominence/openweathermap/api/enums/OneCallResultOptions.java b/src/main/java/com/github/prominence/openweathermap/api/enums/OneCallResultOptions.java new file mode 100644 index 0000000..d66bc8e --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/enums/OneCallResultOptions.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.enums; + +/** + * The enum One call result options. + */ +public enum OneCallResultOptions { + /** + * Current one call result options. + */ + CURRENT("current"), + /** + * Minutely one call result options. + */ + MINUTELY("minutely"), + /** + * Hourly one call result options. + */ + HOURLY("hourly"), + /** + * Daily one call result options. + */ + DAILY("daily"), + /** + * Alerts one call result options. + */ + ALERTS("alerts"); + + private final String value; + + OneCallResultOptions(String value) { + this.value = value; + } + + /** + * Gets value. + * + * @return the value + */ + public String getValue() { + return value; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/enums/WeatherCondition.java b/src/main/java/com/github/prominence/openweathermap/api/enums/WeatherCondition.java new file mode 100644 index 0000000..bb42470 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/enums/WeatherCondition.java @@ -0,0 +1,375 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.enums; + +import java.util.Arrays; +import java.util.Optional; + +/** + * Represents weather condition and related information. + * More details here. + */ +public enum WeatherCondition { + // Group 2xx: Thunderstorm + + /** + * The thunderstorm with light rain. + */ + THUNDERSTORM_LIGHT_RAIN(200, "Thunderstorm", "thunderstorm with light rain", "11"), + /** + * The thunderstorm with rain. + */ + THUNDERSTORM_RAIN(201, "Thunderstorm", "thunderstorm with rain", "11"), + /** + * The thunderstorm with heavy rain. + */ + THUNDERSTORM_HEAVY_RAIN(202, "Thunderstorm", "thunderstorm with heavy rain", "11"), + /** + * The light thunderstorm. + */ + THUNDERSTORM_LIGHT(210, "Thunderstorm", "light thunderstorm", "11"), + /** + * The thunderstorm. + */ + THUNDERSTORM(211, "Thunderstorm", "thunderstorm", "11"), + /** + * The heavy thunderstorm. + */ + THUNDERSTORM_HEAVY(212, "Thunderstorm", "heavy thunderstorm", "11"), + /** + * The ragged thunderstorm. + */ + THUNDERSTORM_RAGGED(221, "Thunderstorm", "ragged thunderstorm", "11"), + /** + * The thunderstorm with light drizzle. + */ + THUNDERSTORM_LIGHT_DRIZZLE(230, "Thunderstorm", "thunderstorm with light drizzle", "11"), + /** + * The thunderstorm with drizzle. + */ + THUNDERSTORM_DRIZZLE(231, "Thunderstorm", "thunderstorm with drizzle", "11"), + /** + * The thunderstorm with heavy drizzle. + */ + THUNDERSTORM_HEAVY_DRIZZLE(232, "Thunderstorm", "thunderstorm with heavy drizzle", "11"), + + // Group 3xx: Drizzle + + /** + * The light intensity drizzle. + */ + DRIZZLE_LIGHT(300, "Drizzle", "light intensity drizzle", "09"), + /** + * The drizzle. + */ + DRIZZLE(301, "Drizzle", "drizzle", "09"), + /** + * The heavy intensity drizzle. + */ + DRIZZLE_HEAVY(302, "Drizzle", "heavy intensity drizzle", "09"), + /** + * The light intensity drizzle rain. + */ + DRIZZLE_LIGHT_RAIN(310, "Drizzle", "light intensity drizzle rain", "09"), + /** + * The drizzle rain. + */ + DRIZZLE_RAIN(311, "Drizzle", "drizzle rain", "09"), + /** + * The heavy intensity drizzle rain. + */ + DRIZZLE_HEAVY_RAIN(312, "Drizzle", "heavy intensity drizzle rain", "09"), + /** + * The shower rain and drizzle. + */ + DRIZZLE_SHOWER_RAIN(313, "Drizzle", "shower rain and drizzle", "09"), + /** + * The heavy shower rain and drizzle. + */ + DRIZZLE_HEAVY_SHOWER_RAIN(314, "Drizzle", "heavy shower rain and drizzle", "09"), + /** + * The shower drizzle. + */ + DRIZZLE_SHOWER(321, "Drizzle", "shower drizzle", "09"), + + // Group 5xx: Rain + + /** + * The light rain. + */ + RAIN_LIGHT(500, "Rain", "light rain", "10"), + /** + * The moderate rain. + */ + RAIN_MODERATE(501, "Rain", "moderate rain", "10"), + /** + * The heavy intensity rain. + */ + RAIN_HEAVY(502, "Rain", "heavy intensity rain", "10"), + /** + * The very heavy rain. + */ + RAIN_VERY_HEAVY(503, "Rain", "very heavy rain", "10"), + /** + * The very heavy rain. + */ + RAIN_EXTREME(504, "Rain", "very heavy rain", "10"), + /** + * The freezing rain. + */ + RAIN_FREEZING(511, "Rain", "freezing rain", "10"), + /** + * The light intensity shower rain. + */ + RAIN_LIGHT_SHOWER(520, "Rain", "light intensity shower rain", "10"), + /** + * The shower rain. + */ + RAIN_SHOWER(521, "Rain", "shower rain", "10"), + /** + * The heavy intensity shower rain. + */ + RAIN_HEAVY_SHOWER(522, "Rain", "heavy intensity shower rain", "10"), + /** + * The ragged shower rain. + */ + RAIN_RAGGED_SHOWER(531, "Rain", "ragged shower rain", "10"), + + // Group 6xx: Snow + + /** + * The light snow. + */ + SNOW_LIGHT(600, "Snow", "light snow", "13"), + /** + * The snow. + */ + SNOW(601, "Snow", "snow", "13"), + /** + * The heavy snow. + */ + SNOW_HEAVY(602, "Snow", "heavy snow", "13"), + /** + * The sleet. + */ + SNOW_SLEET(611, "Snow", "sleet", "13"), + /** + * The light shower sleet. + */ + SNOW_LIGHT_SHOWER_SLEET(612, "Snow", "light shower sleet", "13"), + /** + * The shower sleet. + */ + SNOW_SHOWER_SLEET(613, "Snow", "shower sleet", "13"), + /** + * The light rain and snow. + */ + SNOW_LIGHT_RAIN_AND_SNOW(615, "Snow", "light rain and snow", "13"), + /** + * The rain and snow. + */ + SNOW_RAIN_AND_SNOW(616, "Snow", "rain and snow", "13"), + /** + * The light shower snow. + */ + SNOW_LIGHT_SHOWER_SNOW(620, "Snow", "light shower snow", "13"), + /** + * The shower snow. + */ + SNOW_SHOWER_SNOW(621, "Snow", "shower snow", "13"), + /** + * The heavy shower snow. + */ + SNOW_HEAVY_SHOWER_SNOW(622, "Snow", "heavy shower snow", "13"), + + // Group 7xx: Atmosphere + + /** + * The mist. + */ + MIST(701, "Mist", "mist", "50"), + /** + * The smoke. + */ + SMOKE(711, "Smoke", "smoke", "50"), + /** + * The haze. + */ + HAZE(721, "Haze", "haze", "50"), + /** + * The sand/dust whirls. + */ + DUST_WHIRLS(731, "Dust", "sand/dust whirls", "50"), + /** + * The fog. + */ + FOG(741, "Fog", "fog", "50"), + /** + * The sand. + */ + SAND(751, "Sand", "sand", "50"), + /** + * The dust. + */ + DUST(761, "Dust", "dust", "50"), + /** + * The volcanic ash. + */ + ASH(762, "Ash", "volcanic ash", "50"), + /** + * The squall. + */ + SQUALL(771, "Squall", "squalls", "50"), + /** + * The tornado. + */ + TORNADO(781, "Tornado", "tornado", "50"), + + // Group 800: Clear + + /** + * The clear sky. + */ + CLEAR(800, "Clear", "clear sky", "01"), + + // Group 80x: Clouds + + /** + * A few clouds: 11-25%. + */ + CLOUDS_FEW(801, "Clouds", "few clouds: 11-25%", "02"), + /** + * A scattered clouds: 25-50%. + */ + CLOUDS_SCATTERED(802, "Clouds", "scattered clouds: 25-50%", "03"), + /** + * A broken clouds: 51-84%. + */ + CLOUDS_BROKEN(803, "Clouds", "broken clouds: 51-84%", "04"), + /** + * An overcast clouds: 85-100%. + */ + CLOUDS_OVERCAST(804, "Clouds", "overcast clouds: 85-100%", "04"); + + + private final int id; + private final String name; + private final String description; + private final String iconId; + + private WeatherCondition(int id, String name, String description, String iconId) { + this.id = id; + this.name = name; + this.description = description; + this.iconId = iconId; + } + + /** + * Gets id. + * + * @return the id + */ + public int getId() { + return id; + } + + /** + * Gets name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Gets description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Gets day icon id. + * + * @return the day icon id + */ + public String getDayIconId() { + return iconId + 'd'; + } + + /** + * Gets night icon id. + * + * @return the night icon id + */ + public String getNightIconId() { + return iconId + 'n'; + } + + /** + * Gets day icon url. + * + * @return the day icon url + */ + public String getDayIconUrl() { + return getIconUrl(getDayIconId()); + } + + /** + * Gets night icon url. + * + * @return the night icon url + */ + public String getNightIconUrl() { + return getIconUrl(getNightIconId()); + } + + /** + * Gets icon url. + * + * @param iconId the icon id + * @return the icon url + */ + public static String getIconUrl(String iconId) { + return "http://openweathermap.org/img/w/" + iconId + ".png"; + } + + /** + * Gets {@link WeatherCondition} by id. + * + * @param id the id + * @return the by id + */ + public static WeatherCondition getById(int id) { + final Optional optionalWeatherCondition = Arrays.stream(values()).filter(weatherCondition -> weatherCondition.getId() == id).findFirst(); + return optionalWeatherCondition.orElse(null); + } + + @Override + public String toString() { + return "Weather condition(" + id + "): " + name + '(' + description + ')'; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/Coordinate.java b/src/main/java/com/github/prominence/openweathermap/api/model/Coordinate.java index a96acfc..b46a9fd 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/Coordinate.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/Coordinate.java @@ -31,9 +31,8 @@ public class Coordinate { private double latitude; private double longitude; - private Coordinate(double latitude, double longitude) { - this.latitude = latitude; - this.longitude = longitude; + private Coordinate() { + } /** @@ -42,14 +41,11 @@ public class Coordinate { * @param longitude longitude * @return coordinate object. */ - public static Coordinate withValues(double latitude, double longitude) { - if (latitude < -90 || latitude > 90) { - throw new IllegalArgumentException("Latitude value must be in the next range: [-90.0; 90.0]."); - } - if (longitude < -180 || longitude > 180) { - throw new IllegalArgumentException("Longitude value must be in the next range: [-180.0; 180.0]."); - } - return new Coordinate(latitude, longitude); + public static Coordinate of(double latitude, double longitude) { + final Coordinate coordinate = new Coordinate(); + coordinate.setLatitude(latitude); + coordinate.setLongitude(longitude); + return coordinate; } /** diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/Temperature.java b/src/main/java/com/github/prominence/openweathermap/api/model/Temperature.java index 5ec1fec..66b4fc6 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/Temperature.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/Temperature.java @@ -154,7 +154,7 @@ public class Temperature { @Override public String toString() { - StringBuilder stringBuilder = new StringBuilder(); + final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Temperature: "); stringBuilder.append(value); stringBuilder.append(' '); diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/WeatherState.java b/src/main/java/com/github/prominence/openweathermap/api/model/WeatherState.java new file mode 100644 index 0000000..c729a2e --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/WeatherState.java @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model; + +import com.github.prominence.openweathermap.api.enums.WeatherCondition; + +import java.util.Objects; + +/** + * The type Weather state. + */ +public class WeatherState { + private final int id; + private final String name; + private final String description; + private String iconId; + private final WeatherCondition weatherConditionEnum; + + public WeatherState(Integer id, String name, String description) { + this.id = id; + this.name = name; + this.description = description; + this.weatherConditionEnum = WeatherCondition.getById(id); + } + + /** + * Gets id. + * + * @return the id + */ + public int getId() { + return id; + } + + /** + * Gets name. + * + * @return the name + */ + public String getName() { + return name; + } + + /** + * Gets description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Gets icon id. + * + * @return the icon id + */ + public String getIconId() { + return iconId; + } + + /** + * Sets icon id. + * + * @param iconId the icon id + */ + public void setIconId(String iconId) { + this.iconId = iconId; + } + + /** + * Gets weather condition enum. + * + * @return the weather condition enum + */ + public WeatherCondition getWeatherConditionEnum() { + return weatherConditionEnum; + } + + /** + * Gets weather icon url. + * + * @return the weather icon url + */ + public String getWeatherIconUrl() { + if (iconId != null) { + return WeatherCondition.getIconUrl(iconId); + } + if (weatherConditionEnum != null) { + // return the default one for the current weather condition + return weatherConditionEnum.getDayIconUrl(); + } + return null; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + WeatherState that = (WeatherState) o; + return Objects.equals(id, that.id) && + Objects.equals(name, that.name) && + Objects.equals(description, that.description) && + Objects.equals(iconId, that.iconId); + } + + @Override + public int hashCode() { + return Objects.hash(id, name, description, iconId, weatherConditionEnum); + } + + @Override + public String toString() { + return "Weather state: " + name + "(" + description + ")."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Location.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Location.java index 0d79832..bec34d3 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Location.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Location.java @@ -36,8 +36,8 @@ public class Location { private String name; private String countryCode; - private LocalDateTime sunrise; - private LocalDateTime sunset; + private LocalDateTime sunriseTime; + private LocalDateTime sunsetTime; private ZoneOffset zoneOffset; private Coordinate coordinate; @@ -114,32 +114,32 @@ public class Location { * Returns location sunrise time. * @return sunrise time */ - public LocalDateTime getSunrise() { - return sunrise; + public LocalDateTime getSunriseTime() { + return sunriseTime; } /** * Sets location sunrise time. - * @param sunrise sunrise time + * @param sunriseTime sunrise time */ - public void setSunrise(LocalDateTime sunrise) { - this.sunrise = sunrise; + public void setSunriseTime(LocalDateTime sunriseTime) { + this.sunriseTime = sunriseTime; } /** * Returns location sunset time. * @return sunset time */ - public LocalDateTime getSunset() { - return sunset; + public LocalDateTime getSunsetTime() { + return sunsetTime; } /** * Sets location sunset time. - * @param sunset sunset time + * @param sunsetTime sunset time */ - public void setSunset(LocalDateTime sunset) { - this.sunset = sunset; + public void setSunsetTime(LocalDateTime sunsetTime) { + this.sunsetTime = sunsetTime; } /** @@ -198,8 +198,8 @@ public class Location { return id == location.id && Objects.equals(name, location.name) && Objects.equals(countryCode, location.countryCode) && - Objects.equals(sunrise, location.sunrise) && - Objects.equals(sunset, location.sunset) && + Objects.equals(sunriseTime, location.sunriseTime) && + Objects.equals(sunsetTime, location.sunsetTime) && Objects.equals(zoneOffset, location.zoneOffset) && Objects.equals(coordinate, location.coordinate) && Objects.equals(population, location.population); @@ -207,7 +207,7 @@ public class Location { @Override public int hashCode() { - return Objects.hash(id, name, countryCode, sunrise, sunset, zoneOffset, coordinate, population); + return Objects.hash(id, name, countryCode, sunriseTime, sunsetTime, zoneOffset, coordinate, population); } @Override diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Rain.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Rain.java index f079bc2..99719ae 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Rain.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Rain.java @@ -30,41 +30,41 @@ import java.util.Objects; public class Rain { private static final String DEFAULT_UNIT = "mm"; - private double threeHourRainLevel; + private double threeHourLevel; - private Rain(double threeHourRainLevel) { - this.threeHourRainLevel = threeHourRainLevel; + private Rain(double threeHourLevel) { + this.threeHourLevel = threeHourLevel; } /** * Creates {@link Rain} object with correctness check. - * @param threeHourRainLevel 3-hour rain level value + * @param threeHourLevel 3-hour rain level value * @return rain object. */ - public static Rain withThreeHourLevelValue(double threeHourRainLevel) { - if (threeHourRainLevel < 0) { + public static Rain withThreeHourLevelValue(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Rain level value cannot be negative."); } - return new Rain(threeHourRainLevel); + return new Rain(threeHourLevel); } /** * Returns 3-hour rain level value. * @return 3-hour rain level value */ - public double getThreeHourRainLevel() { - return threeHourRainLevel; + public double getThreeHourLevel() { + return threeHourLevel; } /** * Sets 3-hour rain level value with correctness check. - * @param threeHourRainLevel 3-hour rain level value + * @param threeHourLevel 3-hour rain level value */ - public void setThreeHourRainLevel(double threeHourRainLevel) { - if (threeHourRainLevel < 0) { + public void setThreeHourLevel(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Rain level value cannot be negative."); } - this.threeHourRainLevel = threeHourRainLevel; + this.threeHourLevel = threeHourLevel; } /** @@ -80,18 +80,18 @@ public class Rain { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Rain rain = (Rain) o; - return Double.compare(rain.threeHourRainLevel, threeHourRainLevel) == 0; + return Double.compare(rain.threeHourLevel, threeHourLevel) == 0; } @Override public int hashCode() { - return Objects.hash(threeHourRainLevel); + return Objects.hash(threeHourLevel); } @Override public String toString() { return "3-hour rain level: " + - threeHourRainLevel + ' ' + + threeHourLevel + ' ' + getUnit(); } } diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Snow.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Snow.java index d0cea01..4363b52 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Snow.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/Snow.java @@ -30,41 +30,41 @@ import java.util.Objects; public class Snow { private static final String DEFAULT_UNIT = "mm"; - private double threeHourSnowLevel; + private double threeHourLevel; - private Snow(double threeHourSnowLevel) { - this.threeHourSnowLevel = threeHourSnowLevel; + private Snow(double threeHourLevel) { + this.threeHourLevel = threeHourLevel; } /** * Creates {@link Snow} object with correctness check. - * @param threeHourSnowLevel 3-hour snow level value + * @param threeHourLevel 3-hour snow level value * @return snow object. */ - public static Snow withThreeHourLevelValue(double threeHourSnowLevel) { - if (threeHourSnowLevel < 0) { + public static Snow withThreeHourLevelValue(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Snow level value cannot be negative."); } - return new Snow(threeHourSnowLevel); + return new Snow(threeHourLevel); } /** * Returns 3-hour snow level value. * @return 3-hour snow level value */ - public double getThreeHourSnowLevel() { - return threeHourSnowLevel; + public double getThreeHourLevel() { + return threeHourLevel; } /** * Sets 3-hour snow level value with correctness check. - * @param threeHourSnowLevel 3-hour snow level value + * @param threeHourLevel 3-hour snow level value */ - public void setThreeHourSnowLevel(double threeHourSnowLevel) { - if (threeHourSnowLevel < 0) { + public void setThreeHourLevel(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Snow level value cannot be negative."); } - this.threeHourSnowLevel = threeHourSnowLevel; + this.threeHourLevel = threeHourLevel; } /** @@ -80,18 +80,18 @@ public class Snow { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Snow snow = (Snow) o; - return Double.compare(snow.threeHourSnowLevel, threeHourSnowLevel) == 0; + return Double.compare(snow.threeHourLevel, threeHourLevel) == 0; } @Override public int hashCode() { - return Objects.hash(threeHourSnowLevel); + return Objects.hash(threeHourLevel); } @Override public String toString() { return "3-hour snow level: " + - threeHourSnowLevel + ' ' + + threeHourLevel + ' ' + getUnit(); } } diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecast.java b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecast.java index 1a3b07e..e5c7a22 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecast.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecast.java @@ -31,12 +31,9 @@ import java.util.Objects; * Represents weather forecast information for a particular timestamp. */ public class WeatherForecast { - private String state; - private String description; - private String weatherIconId; - private LocalDateTime forecastTime; + private WeatherState weatherState; private Temperature temperature; private AtmosphericPressure atmosphericPressure; private Humidity humidity; @@ -49,100 +46,6 @@ public class WeatherForecast { private String forecastTimeISO; private DayTime dayTime; - private WeatherForecast(String state, String description) { - this.state = state; - this.description = description; - } - - /** - * For value weather forecast. - * - * @param state the state - * @param description the description - * @return the weather forecast - */ - public static WeatherForecast forValue(String state, String description) { - if (state == null) { - throw new IllegalArgumentException("State must be set."); - } - if (description == null) { - throw new IllegalArgumentException("Description must be set."); - } - return new WeatherForecast(state, description); - } - - /** - * Gets state. - * - * @return the state - */ - public String getState() { - return state; - } - - /** - * Sets state. - * - * @param state the state - */ - public void setState(String state) { - if (state == null) { - throw new IllegalArgumentException("State must be not null."); - } - this.state = state; - } - - /** - * Gets description. - * - * @return the description - */ - public String getDescription() { - return description; - } - - /** - * Sets description. - * - * @param description the description - */ - public void setDescription(String description) { - if (description == null) { - throw new IllegalArgumentException("Description must be not null."); - } - this.description = description; - } - - /** - * Gets weather icon ID. - * - * @return the weather icon ID - */ - public String getWeatherIconId() { - return weatherIconId; - } - - /** - * Sets weather icon ID. - * - * @param weatherIconId the weather icon ID - */ - public void setWeatherIconId(String weatherIconId) { - this.weatherIconId = weatherIconId; - } - - /** - * Gets weather icon url. - * - * @return the weather icon url - */ - public String getWeatherIconUrl() { - if (weatherIconId != null) { - return "https://openweathermap.org/img/w/" + weatherIconId + ".png"; - } - return null; - } - /** * Gets forecast time. * @@ -161,6 +64,24 @@ public class WeatherForecast { this.forecastTime = forecastTime; } + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; + } + /** * Gets temperature. * @@ -328,10 +249,8 @@ public class WeatherForecast { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; WeatherForecast that = (WeatherForecast) o; - return Objects.equals(state, that.state) && - Objects.equals(description, that.description) && - Objects.equals(weatherIconId, that.weatherIconId) && - Objects.equals(forecastTime, that.forecastTime) && + return Objects.equals(forecastTime, that.forecastTime) && + Objects.equals(weatherState, that.weatherState) && Objects.equals(temperature, that.temperature) && Objects.equals(atmosphericPressure, that.atmosphericPressure) && Objects.equals(humidity, that.humidity) && @@ -345,7 +264,7 @@ public class WeatherForecast { @Override public int hashCode() { - return Objects.hash(state, description, weatherIconId, forecastTime, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds, forecastTimeISO, dayTime); + return Objects.hash(forecastTime, weatherState, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds, forecastTimeISO, dayTime); } @Override @@ -353,8 +272,10 @@ public class WeatherForecast { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append("Timestamp: "); stringBuilder.append(forecastTimeISO); - stringBuilder.append(", Weather: "); - stringBuilder.append(description); + if (weatherState != null) { + stringBuilder.append(", Weather: "); + stringBuilder.append(weatherState.getDescription()); + } if (temperature != null) { stringBuilder.append(", "); stringBuilder.append(temperature.getValue()); @@ -373,13 +294,13 @@ public class WeatherForecast { } if (rain != null) { stringBuilder.append(", Rain: "); - stringBuilder.append(rain.getThreeHourRainLevel()); + stringBuilder.append(rain.getThreeHourLevel()); stringBuilder.append(' '); stringBuilder.append(rain.getUnit()); } if (snow != null) { stringBuilder.append(", Snow: "); - stringBuilder.append(snow.getThreeHourSnowLevel()); + stringBuilder.append(snow.getThreeHourLevel()); stringBuilder.append(' '); stringBuilder.append(snow.getUnit()); } diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressure.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressure.java new file mode 100644 index 0000000..b36012d --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressure.java @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import java.util.Objects; + +/** + * The AtmosphericPressure type represents atmospheric pressure value. + * Its value can only be a double in [0, +∞) range. + */ +public class AtmosphericPressure { + private static final String DEFAULT_UNIT = "hPa"; + + private double seaLevelValue; + + private AtmosphericPressure() { + } + + /** + * Static method for {@link AtmosphericPressure} creation with value checking. + * @param seaLevelValue atmospheric pressure value. + * @return instantiated {@link AtmosphericPressure} object. + */ + public static AtmosphericPressure withValue(double seaLevelValue) { + final AtmosphericPressure atmosphericPressure = new AtmosphericPressure(); + atmosphericPressure.setSeaLevelValue(seaLevelValue); + return atmosphericPressure; + } + + /** + * Gets sea level value. + * + * @return the sea level value. + */ + public Double getSeaLevelValue() { + return seaLevelValue; + } + + /** + * Sets sea level value. + * + * @param seaLevelValue the sea level value. + * @throws IllegalArgumentException in case if provided value isn't in allowed range. + */ + public void setSeaLevelValue(double seaLevelValue) { + if (seaLevelValue < 0) { + throw new IllegalArgumentException("Atmospheric pressure value must be in [0, +∞) range."); + } + this.seaLevelValue = seaLevelValue; + } + + /** + * Returns pressure unitSystem. Constantly equals to 'hPa'. + * + * @return the pressure unitSystem. + */ + public String getUnit() { + return DEFAULT_UNIT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + AtmosphericPressure that = (AtmosphericPressure) o; + return Double.compare(that.seaLevelValue, seaLevelValue) == 0; + } + + @Override + public int hashCode() { + return Objects.hash(seaLevelValue); + } + + @Override + public String toString() { + return "Pressure: " + seaLevelValue + ' ' + getUnit(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Current.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Current.java new file mode 100644 index 0000000..f619512 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Current.java @@ -0,0 +1,320 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Current. + */ +public class Current { + protected LocalDateTime forecastTime; + protected LocalDateTime sunriseTime; + protected LocalDateTime sunsetTime; + + protected WeatherState weatherState; + protected Temperature temperature; + protected AtmosphericPressure atmosphericPressure; + protected Humidity humidity; + protected Clouds clouds; + protected Double uvIndex; + protected Double visibilityInMetres; + protected Wind wind; + protected Rain rain; + protected Snow snow; + + /** + * Gets forecast time. + * + * @return the forecast time + */ + public LocalDateTime getForecastTime() { + return forecastTime; + } + + /** + * Sets forecast time. + * + * @param forecastTime the forecast time + */ + public void setForecastTime(LocalDateTime forecastTime) { + this.forecastTime = forecastTime; + } + + /** + * Gets sunrise time. + * + * @return the sunrise time + */ + public LocalDateTime getSunriseTime() { + return sunriseTime; + } + + /** + * Sets sunrise time. + * + * @param sunriseTime the sunrise time + */ + public void setSunriseTime(LocalDateTime sunriseTime) { + this.sunriseTime = sunriseTime; + } + + /** + * Gets sunset time. + * + * @return the sunset time + */ + public LocalDateTime getSunsetTime() { + return sunsetTime; + } + + /** + * Sets sunset time. + * + * @param sunsetTime the sunset time + */ + public void setSunsetTime(LocalDateTime sunsetTime) { + this.sunsetTime = sunsetTime; + } + + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; + } + + /** + * Gets temperature. + * + * @return the temperature + */ + public Temperature getTemperature() { + return temperature; + } + + /** + * Sets temperature. + * + * @param temperature the temperature + */ + public void setTemperature(Temperature temperature) { + this.temperature = temperature; + } + + /** + * Gets atmospheric pressure. + * + * @return the atmospheric pressure + */ + public AtmosphericPressure getAtmosphericPressure() { + return atmosphericPressure; + } + + /** + * Sets atmospheric pressure. + * + * @param atmosphericPressure the atmospheric pressure + */ + public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) { + this.atmosphericPressure = atmosphericPressure; + } + + /** + * Gets humidity. + * + * @return the humidity + */ + public Humidity getHumidity() { + return humidity; + } + + /** + * Sets humidity. + * + * @param humidity the humidity + */ + public void setHumidity(Humidity humidity) { + this.humidity = humidity; + } + + /** + * Gets clouds. + * + * @return the clouds + */ + public Clouds getClouds() { + return clouds; + } + + /** + * Sets clouds. + * + * @param clouds the clouds + */ + public void setClouds(Clouds clouds) { + this.clouds = clouds; + } + + /** + * Gets uv index. + * + * @return the uv index + */ + public Double getUvIndex() { + return uvIndex; + } + + /** + * Sets uv index. + * + * @param uvIndex the uv index + */ + public void setUvIndex(Double uvIndex) { + if (uvIndex != null && uvIndex < 0) { + throw new IllegalArgumentException("UV index must not be negative."); + } + this.uvIndex = uvIndex; + } + + /** + * Gets visibility in metres. + * + * @return the visibility in metres + */ + public Double getVisibilityInMetres() { + return visibilityInMetres; + } + + /** + * Sets visibility in metres. + * + * @param visibilityInMetres the visibility in metres + */ + public void setVisibilityInMetres(Double visibilityInMetres) { + if (visibilityInMetres != null && visibilityInMetres < 0) { + throw new IllegalArgumentException("Visibility must not be negative."); + } + this.visibilityInMetres = visibilityInMetres; + } + + /** + * Gets wind. + * + * @return the wind + */ + public Wind getWind() { + return wind; + } + + /** + * Sets wind. + * + * @param wind the wind + */ + public void setWind(Wind wind) { + this.wind = wind; + } + + /** + * Gets rain. + * + * @return the rain + */ + public Rain getRain() { + return rain; + } + + /** + * Sets rain. + * + * @param rain the rain + */ + public void setRain(Rain rain) { + this.rain = rain; + } + + /** + * Gets snow. + * + * @return the snow + */ + public Snow getSnow() { + return snow; + } + + /** + * Sets snow. + * + * @param snow the snow + */ + public void setSnow(Snow snow) { + this.snow = snow; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Current current = (Current) o; + return Objects.equals(forecastTime, current.forecastTime) && + Objects.equals(sunriseTime, current.sunriseTime) && + Objects.equals(sunsetTime, current.sunsetTime) && + Objects.equals(weatherState, current.weatherState) && + Objects.equals(temperature, current.temperature) && + Objects.equals(atmosphericPressure, current.atmosphericPressure) && + Objects.equals(humidity, current.humidity) && + Objects.equals(clouds, current.clouds) && + Objects.equals(uvIndex, current.uvIndex) && + Objects.equals(visibilityInMetres, current.visibilityInMetres) && + Objects.equals(wind, current.wind) && + Objects.equals(rain, current.rain) && + Objects.equals(snow, current.snow); + } + + @Override + public int hashCode() { + return Objects.hash(forecastTime, sunriseTime, sunsetTime, weatherState, temperature, atmosphericPressure, humidity, clouds, uvIndex, visibilityInMetres, wind, rain, snow); + } + + @Override + public String toString() { + return "Current weather information forecasted for " + forecastTime + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Rain.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Rain.java new file mode 100644 index 0000000..cf93537 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Rain.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import java.util.Objects; + +/** + * Represents rain information. + */ +public class Rain { + private static final String DEFAULT_UNIT = "mm"; + + private double oneHourLevel; + + private Rain() { + } + + /** + * Creates {@link Rain} object with correctness check. + * + * @param oneHourLevel 1-hour rain level value + * @return rain object. + */ + public static Rain withOneHourLevelValue(double oneHourLevel) { + final Rain rain = new Rain(); + rain.setOneHourLevel(oneHourLevel); + return rain; + } + + /** + * Gets one hour rain level. + * + * @return the one hour rain level + */ + public double getOneHourLevel() { + return oneHourLevel; + } + + /** + * Sets one hour rain level. + * + * @param oneHourLevel the one hour rain level + */ + public void setOneHourLevel(double oneHourLevel) { + if (oneHourLevel < 0) { + throw new IllegalArgumentException("Rain level value cannot be negative."); + } + this.oneHourLevel = oneHourLevel; + } + + /** + * Gets unit. + * + * @return the unit + */ + public String getUnit() { + return DEFAULT_UNIT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Rain)) return false; + Rain rain = (Rain) o; + return Objects.equals(oneHourLevel, rain.oneHourLevel); + } + + @Override + public int hashCode() { + return Objects.hash(oneHourLevel); + } + + @Override + public String toString() { + return "1-hour rain level: " + + oneHourLevel + ' ' + + getUnit(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Snow.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Snow.java new file mode 100644 index 0000000..5c7d766 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Snow.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import java.util.Objects; + +/** + * Represents snow information. + */ +public class Snow { + private static final String DEFAULT_UNIT = "mm"; + + private double oneHourLevel; + + private Snow() { + } + + /** + * Creates {@link Snow} object with correctness check. + * + * @param oneHourLevel 1-hour snow level value + * @return snow object. + */ + public static Snow withOneHourLevelValue(double oneHourLevel) { + final Snow snow = new Snow(); + snow.setOneHourLevel(oneHourLevel); + return snow; + } + + /** + * Gets one hour snow level. + * + * @return the one hour snow level + */ + public double getOneHourLevel() { + return oneHourLevel; + } + + /** + * Sets one hour snow level. + * + * @param oneHourLevel the one hour snow level + */ + public void setOneHourLevel(double oneHourLevel) { + if (oneHourLevel < 0) { + throw new IllegalArgumentException("Snow level value cannot be negative."); + } + this.oneHourLevel = oneHourLevel; + } + + /** + * Gets unit. + * + * @return the unit + */ + public String getUnit() { + return DEFAULT_UNIT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Snow)) return false; + Snow snow = (Snow) o; + return Objects.equals(oneHourLevel, snow.oneHourLevel); + } + + @Override + public int hashCode() { + return Objects.hash(oneHourLevel); + } + + @Override + public String toString() { + return "1-hour snow level: " + + oneHourLevel + ' ' + + getUnit(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Temperature.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Temperature.java new file mode 100644 index 0000000..d4295fc --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Temperature.java @@ -0,0 +1,143 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import java.util.Objects; + +/** + * Represents temperature values and unit. + */ +public class Temperature { + private double value; + private Double feelsLike; + private Double dewPoint; + private String unit; + + private Temperature() { + } + + /** + * Creates {@link Temperature} object with correctness check. + * @param value temperature value + * @param unit temperature unit + * @return temperature object + */ + public static Temperature withValue(double value, String unit) { + final Temperature temperature = new Temperature(); + temperature.setValue(value); + temperature.setUnit(unit); + return temperature; + } + + /** + * Returns temperature value. + * @return value + */ + public double getValue() { + return value; + } + + /** + * Sets temperature value. + * @param value temperature + */ + public void setValue(double value) { + this.value = value; + } + + /** + * Returns 'feels like' temperature value. + * @return 'feels like' temperature value + */ + public Double getFeelsLike() { + return feelsLike; + } + + /** + * Sets 'feels like' temperature value. + * @param feelsLike 'feels like' temperature + */ + public void setFeelsLike(Double feelsLike) { + this.feelsLike = feelsLike; + } + + public Double getDewPoint() { + return dewPoint; + } + + public void setDewPoint(Double dewPoint) { + this.dewPoint = dewPoint; + } + + /** + * Returns temperature unit. + * @return unit + */ + public String getUnit() { + return unit; + } + + /** + * Sets temperature unit with correctness check. + * @param unit temperature unit + */ + public void setUnit(String unit) { + if (unit == null) { + throw new IllegalArgumentException("Unit must be set."); + } + this.unit = unit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Temperature)) return false; + Temperature that = (Temperature) o; + return Double.compare(that.value, value) == 0 && + Objects.equals(feelsLike, that.feelsLike) && + Objects.equals(dewPoint, that.dewPoint) && + Objects.equals(unit, that.unit); + } + + @Override + public int hashCode() { + return Objects.hash(value, feelsLike, dewPoint, unit); + } + + @Override + public String toString() { + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Temperature: "); + stringBuilder.append(value); + stringBuilder.append(' '); + stringBuilder.append(unit); + if (feelsLike != null) { + stringBuilder.append(", Feels like: "); + stringBuilder.append(feelsLike); + stringBuilder.append(' '); + stringBuilder.append(unit); + } + + return stringBuilder.toString(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Wind.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Wind.java new file mode 100644 index 0000000..c2ec55a --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/Wind.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import java.util.Objects; + +/** + * The type Wind. + */ +public class Wind { + private double speed; + private Double degrees; + private Double gust; + private String unit; + + private Wind() { + } + + /** + * Creates {@link Wind} object with correctness check. + * @param speed the speed + * @param unit the unitSystem + * @return wind object + */ + public static Wind withValue(double speed, String unit) { + final Wind wind = new Wind(); + wind.setSpeed(speed); + wind.setUnit(unit); + return wind; + } + + /** + * Gets speed. + * + * @return the speed + */ + public double getSpeed() { + return speed; + } + + /** + * Sets speed. + * + * @param speed the speed + */ + public void setSpeed(double speed) { + if (speed < 0) { + throw new IllegalArgumentException("Wind speed value must be in positive or zero."); + } + this.speed = speed; + } + + /** + * Gets gust value. + * @return the gust + */ + public Double getGust() { + return gust; + } + + /** + * Sets gust value. + * @param gust the gust. + */ + public void setGust(double gust) { + if (gust < 0) { + throw new IllegalArgumentException("Gust value must be positive or zero."); + } + this.gust = gust; + } + + /** + * Gets degrees. + * + * @return the degrees + */ + public Double getDegrees() { + return degrees; + } + + /** + * Sets degrees. + * + * @param degrees the degrees + */ + public void setDegrees(double degrees) { + if (degrees < 0 || degrees > 360) { + throw new IllegalArgumentException("Wind direction value must be in [0, 360] range."); + } + this.degrees = degrees; + } + + /** + * Gets unitSystem. + * + * @return the unitSystem + */ + public String getUnit() { + return unit; + } + + /** + * Sets unitSystem. + * + * @param unit the unitSystem + */ + public void setUnit(String unit) { + if (unit == null) { + throw new IllegalArgumentException("Unit must be set."); + } + this.unit = unit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Wind)) return false; + Wind wind = (Wind) o; + return Double.compare(wind.speed, speed) == 0 && + Objects.equals(degrees, wind.degrees) && + Objects.equals(gust, wind.gust) && + Objects.equals(unit, wind.unit); + } + + @Override + public int hashCode() { + return Objects.hash(speed, degrees, gust, unit); + } + + @Override + public String toString() { + String output = "Wind speed: " + speed + " " + unit + + ", degrees: " + degrees; + if (gust != null) { + output += ", Gust: " + gust + " " + unit; + } + return output; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Alert.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Alert.java new file mode 100644 index 0000000..58e22e6 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Alert.java @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Alert. + */ +public class Alert { + private String senderName; + private String eventName; + private LocalDateTime startTime; + private LocalDateTime endTime; + private String description; + + /** + * Instantiates a new Alert. + */ + public Alert() { + } + + /** + * Instantiates a new Alert. + * + * @param senderName the sender name + * @param eventName the event name + * @param startTime the start time + * @param endTime the end time + * @param description the description + */ + public Alert(String senderName, String eventName, LocalDateTime startTime, LocalDateTime endTime, String description) { + this.senderName = senderName; + this.eventName = eventName; + this.startTime = startTime; + this.endTime = endTime; + this.description = description; + } + + /** + * Gets sender name. + * + * @return the sender name + */ + public String getSenderName() { + return senderName; + } + + /** + * Sets sender name. + * + * @param senderName the sender name + */ + public void setSenderName(String senderName) { + this.senderName = senderName; + } + + /** + * Gets event name. + * + * @return the event name + */ + public String getEventName() { + return eventName; + } + + /** + * Sets event name. + * + * @param eventName the event name + */ + public void setEventName(String eventName) { + this.eventName = eventName; + } + + /** + * Gets start time. + * + * @return the start time + */ + public LocalDateTime getStartTime() { + return startTime; + } + + /** + * Sets start time. + * + * @param startTime the start time + */ + public void setStartTime(LocalDateTime startTime) { + this.startTime = startTime; + } + + /** + * Gets end time. + * + * @return the end time + */ + public LocalDateTime getEndTime() { + return endTime; + } + + /** + * Sets end time. + * + * @param endTime the end time + */ + public void setEndTime(LocalDateTime endTime) { + this.endTime = endTime; + } + + /** + * Gets description. + * + * @return the description + */ + public String getDescription() { + return description; + } + + /** + * Sets description. + * + * @param description the description + */ + public void setDescription(String description) { + this.description = description; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Alert alert = (Alert) o; + return Objects.equals(senderName, alert.senderName) && + Objects.equals(eventName, alert.eventName) && + Objects.equals(startTime, alert.startTime) && + Objects.equals(endTime, alert.endTime) && + Objects.equals(description, alert.description); + } + + @Override + public int hashCode() { + return Objects.hash(senderName, eventName, startTime, endTime, description); + } + + @Override + public String toString() { + return senderName + " - " + eventName + "(" + startTime + " - " + endTime + "): " + description; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherData.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherData.java new file mode 100644 index 0000000..836852c --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherData.java @@ -0,0 +1,215 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.model.onecall.Current; + +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Objects; + +/** + * The type Current weather data. + */ +public class CurrentWeatherData { + private Coordinate coordinate; + private ZoneId timezone; + private ZoneOffset timezoneOffset; + + private Current current; + private List minutelyList; + private List hourlyList; + private List dailyList; + private List alerts; + + /** + * Gets coordinate. + * + * @return the coordinate + */ + public Coordinate getCoordinate() { + return coordinate; + } + + /** + * Sets coordinate. + * + * @param coordinate the coordinate + */ + public void setCoordinate(Coordinate coordinate) { + this.coordinate = coordinate; + } + + /** + * Gets timezone. + * + * @return the timezone + */ + public ZoneId getTimezone() { + return timezone; + } + + /** + * Sets timezone. + * + * @param timezone the timezone + */ + public void setTimezone(ZoneId timezone) { + this.timezone = timezone; + } + + /** + * Gets timezone offset. + * + * @return the timezone offset + */ + public ZoneOffset getTimezoneOffset() { + return timezoneOffset; + } + + /** + * Sets timezone offset. + * + * @param timezoneOffset the timezone offset + */ + public void setTimezoneOffset(ZoneOffset timezoneOffset) { + this.timezoneOffset = timezoneOffset; + } + + /** + * Gets current. + * + * @return the current + */ + public Current getCurrent() { + return current; + } + + /** + * Sets current. + * + * @param current the current + */ + public void setCurrent(Current current) { + this.current = current; + } + + /** + * Gets minutely list. + * + * @return the minutely list + */ + public List getMinutelyList() { + return minutelyList; + } + + /** + * Sets minutely list. + * + * @param minutelyList the minutely list + */ + public void setMinutelyList(List minutelyList) { + this.minutelyList = minutelyList; + } + + /** + * Gets hourly list. + * + * @return the hourly list + */ + public List getHourlyList() { + return hourlyList; + } + + /** + * Sets hourly list. + * + * @param hourlyList the hourly list + */ + public void setHourlyList(List hourlyList) { + this.hourlyList = hourlyList; + } + + /** + * Gets daily list. + * + * @return the daily list + */ + public List getDailyList() { + return dailyList; + } + + /** + * Sets daily list. + * + * @param dailyList the daily list + */ + public void setDailyList(List dailyList) { + this.dailyList = dailyList; + } + + /** + * Gets alerts. + * + * @return the alerts + */ + public List getAlerts() { + return alerts; + } + + /** + * Sets alerts. + * + * @param alerts the alerts + */ + public void setAlerts(List alerts) { + this.alerts = alerts; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + CurrentWeatherData that = (CurrentWeatherData) o; + return Objects.equals(coordinate, that.coordinate) && + Objects.equals(timezone, that.timezone) && + Objects.equals(timezoneOffset, that.timezoneOffset) && + Objects.equals(current, that.current) && + Objects.equals(minutelyList, that.minutelyList) && + Objects.equals(hourlyList, that.hourlyList) && + Objects.equals(dailyList, that.dailyList) && + Objects.equals(alerts, that.alerts); + } + + @Override + public int hashCode() { + return Objects.hash(coordinate, timezone, timezoneOffset, current, minutelyList, hourlyList, dailyList, alerts); + } + + @Override + public String toString() { + return "Current weather data for " + coordinate + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java new file mode 100644 index 0000000..0fce699 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Daily.java @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure; +import com.github.prominence.openweathermap.api.model.onecall.Wind; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Daily. + */ +public class Daily { + private LocalDateTime forecastTime; + private LocalDateTime sunriseTime; + private LocalDateTime sunsetTime; + + private WeatherState weatherState; + private DailyTemperature temperature; + private AtmosphericPressure atmosphericPressure; + private Humidity humidity; + private Wind wind; + private Clouds clouds; + private Double uvIndex; + private Double probabilityOfPrecipitation; + private DailyRain rain; + private DailySnow snow; + + /** + * Gets forecast time. + * + * @return the forecast time + */ + public LocalDateTime getForecastTime() { + return forecastTime; + } + + /** + * Sets forecast time. + * + * @param forecastTime the forecast time + */ + public void setForecastTime(LocalDateTime forecastTime) { + this.forecastTime = forecastTime; + } + + /** + * Gets sunrise time. + * + * @return the sunrise time + */ + public LocalDateTime getSunriseTime() { + return sunriseTime; + } + + /** + * Sets sunrise time. + * + * @param sunriseTime the sunrise time + */ + public void setSunriseTime(LocalDateTime sunriseTime) { + this.sunriseTime = sunriseTime; + } + + /** + * Gets sunset time. + * + * @return the sunset time + */ + public LocalDateTime getSunsetTime() { + return sunsetTime; + } + + /** + * Sets sunset time. + * + * @param sunsetTime the sunset time + */ + public void setSunsetTime(LocalDateTime sunsetTime) { + this.sunsetTime = sunsetTime; + } + + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; + } + + /** + * Gets temperature. + * + * @return the temperature + */ + public DailyTemperature getTemperature() { + return temperature; + } + + /** + * Sets temperature. + * + * @param temperature the temperature + */ + public void setTemperature(DailyTemperature temperature) { + this.temperature = temperature; + } + + /** + * Gets atmospheric pressure. + * + * @return the atmospheric pressure + */ + public AtmosphericPressure getAtmosphericPressure() { + return atmosphericPressure; + } + + /** + * Sets atmospheric pressure. + * + * @param atmosphericPressure the atmospheric pressure + */ + public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) { + this.atmosphericPressure = atmosphericPressure; + } + + /** + * Gets humidity. + * + * @return the humidity + */ + public Humidity getHumidity() { + return humidity; + } + + /** + * Sets humidity. + * + * @param humidity the humidity + */ + public void setHumidity(Humidity humidity) { + this.humidity = humidity; + } + + /** + * Gets wind. + * + * @return the wind + */ + public Wind getWind() { + return wind; + } + + /** + * Sets wind. + * + * @param wind the wind + */ + public void setWind(Wind wind) { + this.wind = wind; + } + + /** + * Gets clouds. + * + * @return the clouds + */ + public Clouds getClouds() { + return clouds; + } + + /** + * Sets clouds. + * + * @param clouds the clouds + */ + public void setClouds(Clouds clouds) { + this.clouds = clouds; + } + + /** + * Gets uv index. + * + * @return the uv index + */ + public Double getUvIndex() { + return uvIndex; + } + + /** + * Sets uv index. + * + * @param uvIndex the uv index + */ + public void setUvIndex(Double uvIndex) { + if (uvIndex != null && uvIndex < 0) { + throw new IllegalArgumentException("UV index must not be negative."); + } + this.uvIndex = uvIndex; + } + + /** + * Gets probability of precipitation. + * + * @return the probability of precipitation + */ + public Double getProbabilityOfPrecipitation() { + return probabilityOfPrecipitation; + } + + /** + * Sets probability of precipitation. + * + * @param probabilityOfPrecipitation the probability of precipitation + */ + public void setProbabilityOfPrecipitation(Double probabilityOfPrecipitation) { + if (probabilityOfPrecipitation != null && (probabilityOfPrecipitation < 0 || probabilityOfPrecipitation > 100)) { + throw new IllegalArgumentException("Probability of precipitation value must be in [0, 100] range."); + } + this.probabilityOfPrecipitation = probabilityOfPrecipitation; + } + + /** + * Gets rain. + * + * @return the rain + */ + public DailyRain getRain() { + return rain; + } + + /** + * Sets rain. + * + * @param rain the rain + */ + public void setRain(DailyRain rain) { + this.rain = rain; + } + + /** + * Gets snow. + * + * @return the snow + */ + public DailySnow getSnow() { + return snow; + } + + /** + * Sets snow. + * + * @param snow the snow + */ + public void setSnow(DailySnow snow) { + this.snow = snow; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Daily daily = (Daily) o; + return Objects.equals(forecastTime, daily.forecastTime) && + Objects.equals(sunriseTime, daily.sunriseTime) && + Objects.equals(sunsetTime, daily.sunsetTime) && + Objects.equals(weatherState, daily.weatherState) && + Objects.equals(temperature, daily.temperature) && + Objects.equals(atmosphericPressure, daily.atmosphericPressure) && + Objects.equals(humidity, daily.humidity) && + Objects.equals(wind, daily.wind) && + Objects.equals(clouds, daily.clouds) && + Objects.equals(uvIndex, daily.uvIndex) && + Objects.equals(probabilityOfPrecipitation, daily.probabilityOfPrecipitation) && + Objects.equals(rain, daily.rain) && + Objects.equals(snow, daily.snow); + } + + @Override + public int hashCode() { + return Objects.hash(forecastTime, sunriseTime, sunsetTime, weatherState, temperature, atmosphericPressure, humidity, wind, clouds, uvIndex, probabilityOfPrecipitation, rain, snow); + } + + @Override + public String toString() { + final StringBuilder stringBuilder = new StringBuilder(); + stringBuilder.append("Weather on "); + stringBuilder.append(forecastTime); + stringBuilder.append("."); + if (weatherState != null) { + stringBuilder.append(" Weather: "); + stringBuilder.append(weatherState.getDescription()); + stringBuilder.append('.'); + } + if (temperature != null) { + stringBuilder.append(" Temperature(day): "); + stringBuilder.append(temperature.getDay()); + stringBuilder.append(' '); + stringBuilder.append(temperature.getUnit()); + stringBuilder.append('.'); + } + if (atmosphericPressure != null) { + stringBuilder.append(" Atmospheric pressure: "); + stringBuilder.append(atmosphericPressure.getSeaLevelValue()); + stringBuilder.append(' '); + stringBuilder.append(atmosphericPressure.getUnit()); + stringBuilder.append('.'); + } + if (clouds != null) { + stringBuilder.append(" Clouds: "); + stringBuilder.append(clouds.toString()); + stringBuilder.append('.'); + } + if (rain != null) { + stringBuilder.append(" Rain: "); + stringBuilder.append(rain.getValue()); + stringBuilder.append(' '); + stringBuilder.append(rain.getUnit()); + stringBuilder.append('.'); + } + if (snow != null) { + stringBuilder.append(". Snow: "); + stringBuilder.append(snow.getValue()); + stringBuilder.append(' '); + stringBuilder.append(snow.getUnit()); + stringBuilder.append('.'); + } + return stringBuilder.toString(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRain.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRain.java new file mode 100644 index 0000000..936aeb5 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRain.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import java.util.Objects; + +/** + * Represents rain information. + */ +public class DailyRain { + private static final String DEFAULT_UNIT = "mm"; + + private double value; + + private DailyRain() { + } + + /** + * Creates {@link DailyRain} object with correctness check. + * + * @param value 1-hour rain level value + * @return rain object. + */ + public static DailyRain withValue(double value) { + final DailyRain rain = new DailyRain(); + rain.setValue(value); + return rain; + } + + /** + * Gets one hour rain level. + * + * @return the one hour rain level + */ + public double getValue() { + return value; + } + + /** + * Sets one hour rain level. + * + * @param value the one hour rain level + */ + public void setValue(double value) { + if (value < 0) { + throw new IllegalArgumentException("Rain level value cannot be negative."); + } + this.value = value; + } + + /** + * Gets unit. + * + * @return the unit + */ + public String getUnit() { + return DEFAULT_UNIT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DailyRain)) return false; + DailyRain rain = (DailyRain) o; + return Objects.equals(value, rain.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "Rain level: " + + value + + getUnit(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnow.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnow.java new file mode 100644 index 0000000..40cd814 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnow.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import java.util.Objects; + +/** + * Represents snow information. + */ +public class DailySnow { + private static final String DEFAULT_UNIT = "mm"; + + private double value; + + private DailySnow() { + } + + /** + * Creates {@link DailySnow} object with correctness check. + * + * @param value 1-hour snow level value + * @return snow object. + */ + public static DailySnow withValue(double value) { + final DailySnow snow = new DailySnow(); + snow.setValue(value); + return snow; + } + + /** + * Gets one hour snow level. + * + * @return the one hour snow level + */ + public double getValue() { + return value; + } + + /** + * Sets one hour snow level. + * + * @param value the one hour snow level + */ + public void setValue(double value) { + if (value < 0) { + throw new IllegalArgumentException("Snow level value cannot be negative."); + } + this.value = value; + } + + /** + * Gets unit. + * + * @return the unit + */ + public String getUnit() { + return DEFAULT_UNIT; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof DailySnow)) return false; + DailySnow snow = (DailySnow) o; + return Objects.equals(value, snow.value); + } + + @Override + public int hashCode() { + return Objects.hash(value); + } + + @Override + public String toString() { + return "Snow level: " + + value + + getUnit(); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperature.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperature.java new file mode 100644 index 0000000..f4dc382 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperature.java @@ -0,0 +1,283 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import java.util.Objects; + +/** + * The type Daily temperature. + */ +public class DailyTemperature { + private Double morning; + private Double morningFeelsLike; + private Double day; + private Double dayFeelsLike; + private Double eve; + private Double eveFeelsLike; + private Double night; + private Double nightFeelsLike; + private Double min; + private Double max; + private Double dewPoint; + private String unit; + + /** + * Gets morning temperature. + * + * @return the morning + */ + public Double getMorning() { + return morning; + } + + /** + * Sets morning temperature. + * + * @param morning the morning + */ + public void setMorning(Double morning) { + this.morning = morning; + } + + /** + * Gets morning feels like temperature. + * + * @return the morning feels like temperature + */ + public Double getMorningFeelsLike() { + return morningFeelsLike; + } + + /** + * Sets morning feels like temperature. + * + * @param morningFeelsLike the morning feels like temperature + */ + public void setMorningFeelsLike(Double morningFeelsLike) { + this.morningFeelsLike = morningFeelsLike; + } + + /** + * Gets day temperature. + * + * @return the day temperature + */ + public Double getDay() { + return day; + } + + /** + * Sets day temperature. + * + * @param day the day temperature + */ + public void setDay(Double day) { + this.day = day; + } + + /** + * Gets day feels like temperature. + * + * @return the day feels like temperature + */ + public Double getDayFeelsLike() { + return dayFeelsLike; + } + + /** + * Sets day feels like temperature. + * + * @param dayFeelsLike the day feels like temperature + */ + public void setDayFeelsLike(Double dayFeelsLike) { + this.dayFeelsLike = dayFeelsLike; + } + + /** + * Gets eve temperature. + * + * @return the eve temperature + */ + public Double getEve() { + return eve; + } + + /** + * Sets eve temperature. + * + * @param eve the eve temperature + */ + public void setEve(Double eve) { + this.eve = eve; + } + + /** + * Gets eve feels like temperature. + * + * @return the eve feels like temperature + */ + public Double getEveFeelsLike() { + return eveFeelsLike; + } + + /** + * Sets eve feels like temperature. + * + * @param eveFeelsLike the eve feels like temperature + */ + public void setEveFeelsLike(Double eveFeelsLike) { + this.eveFeelsLike = eveFeelsLike; + } + + /** + * Gets night temperature. + * + * @return the night temperature + */ + public Double getNight() { + return night; + } + + /** + * Sets night temperature. + * + * @param night the night temperature + */ + public void setNight(Double night) { + this.night = night; + } + + /** + * Gets night feels like temperature. + * + * @return the night feels like temperature + */ + public Double getNightFeelsLike() { + return nightFeelsLike; + } + + /** + * Sets night feels like temperature. + * + * @param nightFeelsLike the night feels like temperature + */ + public void setNightFeelsLike(Double nightFeelsLike) { + this.nightFeelsLike = nightFeelsLike; + } + + /** + * Gets min temperature. + * + * @return the min temperature + */ + public Double getMin() { + return min; + } + + /** + * Sets min temperature. + * + * @param min the min temperature + */ + public void setMin(Double min) { + this.min = min; + } + + /** + * Gets max temperature. + * + * @return the max temperature + */ + public Double getMax() { + return max; + } + + /** + * Sets max temperature. + * + * @param max the max temperature + */ + public void setMax(Double max) { + this.max = max; + } + + /** + * Gets dew point temperature. + * + * @return the dew point temperature + */ + public Double getDewPoint() { + return dewPoint; + } + + /** + * Sets dew point temperature. + * + * @param dewPoint the dew point temperature + */ + public void setDewPoint(Double dewPoint) { + this.dewPoint = dewPoint; + } + + /** + * Gets unit temperature. + * + * @return the unit temperature + */ + public String getUnit() { + return unit; + } + + /** + * Sets unit temperature. + * + * @param unit the unit temperature + */ + public void setUnit(String unit) { + this.unit = unit; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DailyTemperature that = (DailyTemperature) o; + return Objects.equals(that.dewPoint, dewPoint) && + Objects.equals(morning, that.morning) && + Objects.equals(morningFeelsLike, that.morningFeelsLike) && + Objects.equals(day, that.day) && + Objects.equals(dayFeelsLike, that.dayFeelsLike) && + Objects.equals(eve, that.eve) && + Objects.equals(eveFeelsLike, that.eveFeelsLike) && + Objects.equals(night, that.night) && + Objects.equals(nightFeelsLike, that.nightFeelsLike) && + Objects.equals(min, that.min) && + Objects.equals(max, that.max) && + Objects.equals(unit, that.unit); + } + + @Override + public int hashCode() { + return Objects.hash(morning, morningFeelsLike, day, dayFeelsLike, eve, eveFeelsLike, night, nightFeelsLike, min, max, dewPoint, unit); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java new file mode 100644 index 0000000..f2af688 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Hourly.java @@ -0,0 +1,295 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Hourly. + */ +public class Hourly { + private LocalDateTime forecastTime; + + private WeatherState weatherState; + private Temperature temperature; + private AtmosphericPressure atmosphericPressure; + private Humidity humidity; + private Double uvIndex; + private Clouds clouds; + private Double visibilityInMetres; + private Wind wind; + private Double probabilityOfPrecipitation; + private Rain rain; + private Snow snow; + + /** + * Gets forecast time. + * + * @return the forecast time + */ + public LocalDateTime getForecastTime() { + return forecastTime; + } + + /** + * Sets forecast time. + * + * @param forecastTime the forecast time + */ + public void setForecastTime(LocalDateTime forecastTime) { + this.forecastTime = forecastTime; + } + + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; + } + + /** + * Gets temperature. + * + * @return the temperature + */ + public Temperature getTemperature() { + return temperature; + } + + /** + * Sets temperature. + * + * @param temperature the temperature + */ + public void setTemperature(Temperature temperature) { + this.temperature = temperature; + } + + /** + * Gets atmospheric pressure. + * + * @return the atmospheric pressure + */ + public AtmosphericPressure getAtmosphericPressure() { + return atmosphericPressure; + } + + /** + * Sets atmospheric pressure. + * + * @param atmosphericPressure the atmospheric pressure + */ + public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) { + this.atmosphericPressure = atmosphericPressure; + } + + /** + * Gets humidity. + * + * @return the humidity + */ + public Humidity getHumidity() { + return humidity; + } + + /** + * Sets humidity. + * + * @param humidity the humidity + */ + public void setHumidity(Humidity humidity) { + this.humidity = humidity; + } + + /** + * Gets uv index. + * + * @return the uv index + */ + public Double getUvIndex() { + return uvIndex; + } + + /** + * Sets uv index. + * + * @param uvIndex the uv index + */ + public void setUvIndex(Double uvIndex) { + this.uvIndex = uvIndex; + } + + /** + * Gets clouds. + * + * @return the clouds + */ + public Clouds getClouds() { + return clouds; + } + + /** + * Sets clouds. + * + * @param clouds the clouds + */ + public void setClouds(Clouds clouds) { + this.clouds = clouds; + } + + /** + * Gets visibility in metres. + * + * @return the visibility in metres + */ + public Double getVisibilityInMetres() { + return visibilityInMetres; + } + + /** + * Sets visibility in metres. + * + * @param visibilityInMetres the visibility in metres + */ + public void setVisibilityInMetres(Double visibilityInMetres) { + this.visibilityInMetres = visibilityInMetres; + } + + /** + * Gets wind. + * + * @return the wind + */ + public Wind getWind() { + return wind; + } + + /** + * Sets wind. + * + * @param wind the wind + */ + public void setWind(Wind wind) { + this.wind = wind; + } + + /** + * Gets probability of precipitation. + * + * @return the probability of precipitation + */ + public Double getProbabilityOfPrecipitation() { + return probabilityOfPrecipitation; + } + + /** + * Sets probability of precipitation. + * + * @param probabilityOfPrecipitation the probability of precipitation + */ + public void setProbabilityOfPrecipitation(Double probabilityOfPrecipitation) { + this.probabilityOfPrecipitation = probabilityOfPrecipitation; + } + + /** + * Gets rain. + * + * @return the rain + */ + public Rain getRain() { + return rain; + } + + /** + * Sets rain. + * + * @param rain the rain + */ + public void setRain(Rain rain) { + this.rain = rain; + } + + /** + * Gets snow. + * + * @return the snow + */ + public Snow getSnow() { + return snow; + } + + /** + * Sets snow. + * + * @param snow the snow + */ + public void setSnow(Snow snow) { + this.snow = snow; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Hourly hourly = (Hourly) o; + return Objects.equals(forecastTime, hourly.forecastTime) && + Objects.equals(weatherState, hourly.weatherState) && + Objects.equals(temperature, hourly.temperature) && + Objects.equals(atmosphericPressure, hourly.atmosphericPressure) && + Objects.equals(humidity, hourly.humidity) && + Objects.equals(uvIndex, hourly.uvIndex) && + Objects.equals(clouds, hourly.clouds) && + Objects.equals(visibilityInMetres, hourly.visibilityInMetres) && + Objects.equals(wind, hourly.wind) && + Objects.equals(probabilityOfPrecipitation, hourly.probabilityOfPrecipitation) && + Objects.equals(rain, hourly.rain) && + Objects.equals(snow, hourly.snow); + } + + @Override + public int hashCode() { + return Objects.hash(forecastTime, weatherState, temperature, atmosphericPressure, humidity, uvIndex, clouds, visibilityInMetres, wind, probabilityOfPrecipitation, rain, snow); + } + + @Override + public String toString() { + return "Hourly weather information forecasted for " + forecastTime + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Minutely.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Minutely.java new file mode 100644 index 0000000..9e87dfc --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/current/Minutely.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Minutely. + */ +public class Minutely { + private LocalDateTime forecastTime; + private double precipitationVolume; + + private Minutely() { + } + + /** + * With value minutely. + * + * @param forecastTime the forecast time + * @param precipitationVolume the precipitation volume + * @return the minutely + */ + public static Minutely withValue(LocalDateTime forecastTime, double precipitationVolume) { + final Minutely minutely = new Minutely(); + minutely.setForecastTime(forecastTime); + minutely.setPrecipitationVolume(precipitationVolume); + + return minutely; + } + + /** + * Gets forecast time. + * + * @return the forecast time + */ + public LocalDateTime getForecastTime() { + return forecastTime; + } + + private void setForecastTime(LocalDateTime forecastTime) { + Objects.requireNonNull(forecastTime); + this.forecastTime = forecastTime; + } + + /** + * Gets precipitation volume. + * + * @return the precipitation volume + */ + public double getPrecipitationVolume() { + return precipitationVolume; + } + + private void setPrecipitationVolume(double precipitationVolume) { + if (precipitationVolume < 0) { + throw new IllegalArgumentException("Precipitation volume cannot be negative."); + } + this.precipitationVolume = precipitationVolume; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + Minutely minutely = (Minutely) o; + return Double.compare(minutely.precipitationVolume, precipitationVolume) == 0 && Objects.equals(forecastTime, minutely.forecastTime); + } + + @Override + public int hashCode() { + return Objects.hash(forecastTime, precipitationVolume); + } + + @Override + public String toString() { + return "Time: " + forecastTime + ", precipitation volume: " + precipitationVolume; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java new file mode 100644 index 0000000..69e64a5 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeather.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.onecall.*; + +/** + * The type Historical weather. + */ +public class HistoricalWeather extends Current { + @Override + public String toString() { + return "Historical weather information forecasted for " + forecastTime + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherData.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherData.java new file mode 100644 index 0000000..d5da701 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherData.java @@ -0,0 +1,154 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Coordinate; + +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.List; +import java.util.Objects; + +/** + * The type Historical weather data. + */ +public class HistoricalWeatherData { + private Coordinate coordinate; + private ZoneId timezone; + private ZoneOffset timezoneOffset; + + private HistoricalWeather historicalWeather; + private List hourlyList; + + /** + * Gets coordinate. + * + * @return the coordinate + */ + public Coordinate getCoordinate() { + return coordinate; + } + + /** + * Sets coordinate. + * + * @param coordinate the coordinate + */ + public void setCoordinate(Coordinate coordinate) { + this.coordinate = coordinate; + } + + /** + * Gets timezone. + * + * @return the timezone + */ + public ZoneId getTimezone() { + return timezone; + } + + /** + * Sets timezone. + * + * @param timezone the timezone + */ + public void setTimezone(ZoneId timezone) { + this.timezone = timezone; + } + + /** + * Gets timezone offset. + * + * @return the timezone offset + */ + public ZoneOffset getTimezoneOffset() { + return timezoneOffset; + } + + /** + * Sets timezone offset. + * + * @param timezoneOffset the timezone offset + */ + public void setTimezoneOffset(ZoneOffset timezoneOffset) { + this.timezoneOffset = timezoneOffset; + } + + /** + * Gets historical weather. + * + * @return the historical weather + */ + public HistoricalWeather getHistoricalWeather() { + return historicalWeather; + } + + /** + * Sets historical weather. + * + * @param historicalWeather the historical weather + */ + public void setHistoricalWeather(HistoricalWeather historicalWeather) { + this.historicalWeather = historicalWeather; + } + + /** + * Gets hourly list. + * + * @return the hourly list + */ + public List getHourlyList() { + return hourlyList; + } + + /** + * Sets hourly list. + * + * @param hourlyList the hourly list + */ + public void setHourlyList(List hourlyList) { + this.hourlyList = hourlyList; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HistoricalWeatherData that = (HistoricalWeatherData) o; + return Objects.equals(coordinate, that.coordinate) && + Objects.equals(timezone, that.timezone) && + Objects.equals(timezoneOffset, that.timezoneOffset) && + Objects.equals(historicalWeather, that.historicalWeather) && + Objects.equals(hourlyList, that.hourlyList); + } + + @Override + public int hashCode() { + return Objects.hash(coordinate, timezone, timezoneOffset, historicalWeather, hourlyList); + } + + @Override + public String toString() { + return "Historical weather data for " + coordinate + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java new file mode 100644 index 0000000..6b7ec68 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistorical.java @@ -0,0 +1,255 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; + +import java.time.LocalDateTime; +import java.util.Objects; + +/** + * The type Hourly historical. + */ +public class HourlyHistorical { + private LocalDateTime forecastTime; + + private WeatherState weatherState; + private Temperature temperature; + private AtmosphericPressure atmosphericPressure; + private Humidity humidity; + private Clouds clouds; + private Double visibilityInMetres; + private Wind wind; + private Rain rain; + private Snow snow; + + /** + * Gets forecast time. + * + * @return the forecast time + */ + public LocalDateTime getForecastTime() { + return forecastTime; + } + + /** + * Sets forecast time. + * + * @param forecastTime the forecast time + */ + public void setForecastTime(LocalDateTime forecastTime) { + this.forecastTime = forecastTime; + } + + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; + } + + /** + * Gets temperature. + * + * @return the temperature + */ + public Temperature getTemperature() { + return temperature; + } + + /** + * Sets temperature. + * + * @param temperature the temperature + */ + public void setTemperature(Temperature temperature) { + this.temperature = temperature; + } + + /** + * Gets atmospheric pressure. + * + * @return the atmospheric pressure + */ + public AtmosphericPressure getAtmosphericPressure() { + return atmosphericPressure; + } + + /** + * Sets atmospheric pressure. + * + * @param atmosphericPressure the atmospheric pressure + */ + public void setAtmosphericPressure(AtmosphericPressure atmosphericPressure) { + this.atmosphericPressure = atmosphericPressure; + } + + /** + * Gets humidity. + * + * @return the humidity + */ + public Humidity getHumidity() { + return humidity; + } + + /** + * Sets humidity. + * + * @param humidity the humidity + */ + public void setHumidity(Humidity humidity) { + this.humidity = humidity; + } + + /** + * Gets clouds. + * + * @return the clouds + */ + public Clouds getClouds() { + return clouds; + } + + /** + * Sets clouds. + * + * @param clouds the clouds + */ + public void setClouds(Clouds clouds) { + this.clouds = clouds; + } + + /** + * Gets visibility in metres. + * + * @return the visibility in metres + */ + public Double getVisibilityInMetres() { + return visibilityInMetres; + } + + /** + * Sets visibility in metres. + * + * @param visibilityInMetres the visibility in metres + */ + public void setVisibilityInMetres(Double visibilityInMetres) { + this.visibilityInMetres = visibilityInMetres; + } + + /** + * Gets wind. + * + * @return the wind + */ + public Wind getWind() { + return wind; + } + + /** + * Sets wind. + * + * @param wind the wind + */ + public void setWind(Wind wind) { + this.wind = wind; + } + + /** + * Gets rain. + * + * @return the rain + */ + public Rain getRain() { + return rain; + } + + /** + * Sets rain. + * + * @param rain the rain + */ + public void setRain(Rain rain) { + this.rain = rain; + } + + /** + * Gets snow. + * + * @return the snow + */ + public Snow getSnow() { + return snow; + } + + /** + * Sets snow. + * + * @param snow the snow + */ + public void setSnow(Snow snow) { + this.snow = snow; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + HourlyHistorical that = (HourlyHistorical) o; + return Objects.equals(forecastTime, that.forecastTime) && + Objects.equals(weatherState, that.weatherState) && + Objects.equals(temperature, that.temperature) && + Objects.equals(atmosphericPressure, that.atmosphericPressure) && + Objects.equals(humidity, that.humidity) && + Objects.equals(clouds, that.clouds) && + Objects.equals(visibilityInMetres, that.visibilityInMetres) && + Objects.equals(wind, that.wind) && + Objects.equals(rain, that.rain) && + Objects.equals(snow, that.snow); + } + + @Override + public int hashCode() { + return Objects.hash(forecastTime, weatherState, temperature, atmosphericPressure, humidity, clouds, visibilityInMetres, wind, rain, snow); + } + + @Override + public String toString() { + return "Historical hourly information forecasted for " + forecastTime + "."; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Location.java b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Location.java index 0a8cbea..4390e36 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Location.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Location.java @@ -36,8 +36,8 @@ public class Location { private String name; private String countryCode; - private LocalDateTime sunrise; - private LocalDateTime sunset; + private LocalDateTime sunriseTime; + private LocalDateTime sunsetTime; private ZoneOffset zoneOffset; private Coordinate coordinate; @@ -112,32 +112,32 @@ public class Location { * Returns location sunrise time. * @return sunrise time */ - public LocalDateTime getSunrise() { - return sunrise; + public LocalDateTime getSunriseTime() { + return sunriseTime; } /** * Sets location sunrise time. - * @param sunrise sunrise time + * @param sunriseTime sunrise time */ - public void setSunrise(LocalDateTime sunrise) { - this.sunrise = sunrise; + public void setSunriseTime(LocalDateTime sunriseTime) { + this.sunriseTime = sunriseTime; } /** * Returns location sunset time. * @return sunset time */ - public LocalDateTime getSunset() { - return sunset; + public LocalDateTime getSunsetTime() { + return sunsetTime; } /** * Sets location sunset time. - * @param sunset sunset time + * @param sunsetTime sunset time */ - public void setSunset(LocalDateTime sunset) { - this.sunset = sunset; + public void setSunsetTime(LocalDateTime sunsetTime) { + this.sunsetTime = sunsetTime; } /** @@ -180,15 +180,15 @@ public class Location { return id == location.id && Objects.equals(name, location.name) && Objects.equals(countryCode, location.countryCode) && - Objects.equals(sunrise, location.sunrise) && - Objects.equals(sunset, location.sunset) && + Objects.equals(sunriseTime, location.sunriseTime) && + Objects.equals(sunsetTime, location.sunsetTime) && Objects.equals(zoneOffset, location.zoneOffset) && Objects.equals(coordinate, location.coordinate); } @Override public int hashCode() { - return Objects.hash(id, name, countryCode, sunrise, sunset, zoneOffset, coordinate); + return Objects.hash(id, name, countryCode, sunriseTime, sunsetTime, zoneOffset, coordinate); } @Override diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Rain.java b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Rain.java index 78be760..a350b0c 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Rain.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Rain.java @@ -30,8 +30,8 @@ import java.util.Objects; public class Rain { private static final String DEFAULT_UNIT = "mm"; - private Double oneHourRainLevel; - private Double threeHourRainLevel; + private Double oneHourLevel; + private Double threeHourLevel; private Rain() { } @@ -39,38 +39,38 @@ public class Rain { /** * Creates {@link Rain} object with correctness check. * - * @param oneHourRainLevel 1-hour rain level value + * @param oneHourLevel 1-hour rain level value * @return rain object. */ - public static Rain withOneHourLevelValue(double oneHourRainLevel) { - Rain rain = new Rain(); - rain.setOneHourRainLevel(oneHourRainLevel); + public static Rain withOneHourLevelValue(double oneHourLevel) { + final Rain rain = new Rain(); + rain.setOneHourLevel(oneHourLevel); return rain; } /** * Creates {@link Rain} object with correctness check. * - * @param threeHourRainLevel 3-hour rain level value + * @param threeHourLevel 3-hour rain level value * @return rain object. */ - public static Rain withThreeHourLevelValue(double threeHourRainLevel) { - Rain rain = new Rain(); - rain.setThreeHourRainLevel(threeHourRainLevel); + public static Rain withThreeHourLevelValue(double threeHourLevel) { + final Rain rain = new Rain(); + rain.setThreeHourLevel(threeHourLevel); return rain; } /** * Creates {@link Rain} object with correctness check. * - * @param oneHourRainLevel the one hour rain level - * @param threeHourRainLevel the three hour rain level + * @param oneHourLevel the one hour rain level + * @param threeHourLevel the three hour rain level * @return the rain */ - public static Rain withValues(double oneHourRainLevel, double threeHourRainLevel) { - Rain rain = new Rain(); - rain.setOneHourRainLevel(oneHourRainLevel); - rain.setThreeHourRainLevel(threeHourRainLevel); + public static Rain withValues(double oneHourLevel, double threeHourLevel) { + final Rain rain = new Rain(); + rain.setOneHourLevel(oneHourLevel); + rain.setThreeHourLevel(threeHourLevel); return rain; } @@ -79,20 +79,20 @@ public class Rain { * * @return the one hour rain level */ - public Double getOneHourRainLevel() { - return oneHourRainLevel; + public Double getOneHourLevel() { + return oneHourLevel; } /** * Sets one hour rain level. * - * @param oneHourRainLevel the one hour rain level + * @param oneHourLevel the one hour rain level */ - public void setOneHourRainLevel(double oneHourRainLevel) { - if (oneHourRainLevel < 0) { + public void setOneHourLevel(double oneHourLevel) { + if (oneHourLevel < 0) { throw new IllegalArgumentException("Rain level value cannot be negative."); } - this.oneHourRainLevel = oneHourRainLevel; + this.oneHourLevel = oneHourLevel; } /** @@ -100,20 +100,20 @@ public class Rain { * * @return the three hour rain level */ - public Double getThreeHourRainLevel() { - return threeHourRainLevel; + public Double getThreeHourLevel() { + return threeHourLevel; } /** * Sets three hour rain level. * - * @param threeHourRainLevel the three hour rain level + * @param threeHourLevel the three hour rain level */ - public void setThreeHourRainLevel(double threeHourRainLevel) { - if (threeHourRainLevel < 0) { + public void setThreeHourLevel(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Rain level value cannot be negative."); } - this.threeHourRainLevel = threeHourRainLevel; + this.threeHourLevel = threeHourLevel; } /** @@ -130,29 +130,29 @@ public class Rain { if (this == o) return true; if (!(o instanceof Rain)) return false; Rain rain = (Rain) o; - return Objects.equals(oneHourRainLevel, rain.oneHourRainLevel) && - Objects.equals(threeHourRainLevel, rain.threeHourRainLevel); + return Objects.equals(oneHourLevel, rain.oneHourLevel) && + Objects.equals(threeHourLevel, rain.threeHourLevel); } @Override public int hashCode() { - return Objects.hash(oneHourRainLevel, threeHourRainLevel); + return Objects.hash(oneHourLevel, threeHourLevel); } @Override public String toString() { - StringBuilder snowString = new StringBuilder(); - if (oneHourRainLevel != null) { + final StringBuilder snowString = new StringBuilder(); + if (oneHourLevel != null) { snowString.append("1-hour rain level: "); - snowString.append(oneHourRainLevel); + snowString.append(oneHourLevel); snowString.append(getUnit()); } - if (threeHourRainLevel != null) { - if (oneHourRainLevel != null) { + if (threeHourLevel != null) { + if (oneHourLevel != null) { snowString.append(", "); } snowString.append("3-hours rain level: "); - snowString.append(threeHourRainLevel); + snowString.append(threeHourLevel); snowString.append(getUnit()); } return snowString.toString(); diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Snow.java b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Snow.java index 66991fd..305dcd2 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Snow.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Snow.java @@ -30,8 +30,8 @@ import java.util.Objects; public class Snow { private static final String DEFAULT_UNIT = "mm"; - private Double oneHourSnowLevel; - private Double threeHourSnowLevel; + private Double oneHourLevel; + private Double threeHourLevel; private Snow() { } @@ -39,38 +39,38 @@ public class Snow { /** * Creates {@link Snow} object with correctness check. * - * @param oneHourSnowLevel 1-hour snow level value + * @param oneHourLevel 1-hour snow level value * @return snow object. */ - public static Snow withOneHourLevelValue(double oneHourSnowLevel) { - Snow snow = new Snow(); - snow.setOneHourSnowLevel(oneHourSnowLevel); + public static Snow withOneHourLevelValue(double oneHourLevel) { + final Snow snow = new Snow(); + snow.setOneHourLevel(oneHourLevel); return snow; } /** * Creates {@link Snow} object with correctness check. * - * @param threeHourSnowLevel 3-hour snow level value + * @param threeHourLevel 3-hour snow level value * @return snow object. */ - public static Snow withThreeHourLevelValue(double threeHourSnowLevel) { - Snow snow = new Snow(); - snow.setThreeHourSnowLevel(threeHourSnowLevel); + public static Snow withThreeHourLevelValue(double threeHourLevel) { + final Snow snow = new Snow(); + snow.setThreeHourLevel(threeHourLevel); return snow; } /** * Creates {@link Snow} object with correctness check. * - * @param oneHourSnowLevel the one hour snow level - * @param threeHourSnowLevel the three hour snow level + * @param oneHourLevel the one hour snow level + * @param threeHourLevel the three hour snow level * @return the snow */ - public static Snow withValues(double oneHourSnowLevel, double threeHourSnowLevel) { - Snow snow = new Snow(); - snow.setOneHourSnowLevel(oneHourSnowLevel); - snow.setThreeHourSnowLevel(threeHourSnowLevel); + public static Snow withValues(double oneHourLevel, double threeHourLevel) { + final Snow snow = new Snow(); + snow.setOneHourLevel(oneHourLevel); + snow.setThreeHourLevel(threeHourLevel); return snow; } @@ -79,20 +79,20 @@ public class Snow { * * @return the one hour snow level */ - public Double getOneHourSnowLevel() { - return oneHourSnowLevel; + public Double getOneHourLevel() { + return oneHourLevel; } /** * Sets one hour snow level. * - * @param oneHourSnowLevel the one hour snow level + * @param oneHourLevel the one hour snow level */ - public void setOneHourSnowLevel(double oneHourSnowLevel) { - if (oneHourSnowLevel < 0) { + public void setOneHourLevel(double oneHourLevel) { + if (oneHourLevel < 0) { throw new IllegalArgumentException("Snow level value cannot be negative."); } - this.oneHourSnowLevel = oneHourSnowLevel; + this.oneHourLevel = oneHourLevel; } /** @@ -100,20 +100,20 @@ public class Snow { * * @return the three hour snow level */ - public Double getThreeHourSnowLevel() { - return threeHourSnowLevel; + public Double getThreeHourLevel() { + return threeHourLevel; } /** * Sets three hour snow level. * - * @param threeHourSnowLevel the three hour snow level + * @param threeHourLevel the three hour snow level */ - public void setThreeHourSnowLevel(double threeHourSnowLevel) { - if (threeHourSnowLevel < 0) { + public void setThreeHourLevel(double threeHourLevel) { + if (threeHourLevel < 0) { throw new IllegalArgumentException("Snow level value cannot be negative."); } - this.threeHourSnowLevel = threeHourSnowLevel; + this.threeHourLevel = threeHourLevel; } /** @@ -130,29 +130,29 @@ public class Snow { if (this == o) return true; if (!(o instanceof Snow)) return false; Snow snow = (Snow) o; - return Objects.equals(oneHourSnowLevel, snow.oneHourSnowLevel) && - Objects.equals(threeHourSnowLevel, snow.threeHourSnowLevel); + return Objects.equals(oneHourLevel, snow.oneHourLevel) && + Objects.equals(threeHourLevel, snow.threeHourLevel); } @Override public int hashCode() { - return Objects.hash(oneHourSnowLevel, threeHourSnowLevel); + return Objects.hash(oneHourLevel, threeHourLevel); } @Override public String toString() { - StringBuilder snowString = new StringBuilder(); - if (oneHourSnowLevel != null) { + final StringBuilder snowString = new StringBuilder(); + if (oneHourLevel != null) { snowString.append("1-hour snow level: "); - snowString.append(oneHourSnowLevel); + snowString.append(oneHourLevel); snowString.append(getUnit()); } - if (threeHourSnowLevel != null) { - if (oneHourSnowLevel != null) { + if (threeHourLevel != null) { + if (oneHourLevel != null) { snowString.append(", "); } snowString.append("3-hours snow level: "); - snowString.append(threeHourSnowLevel); + snowString.append(threeHourLevel); snowString.append(getUnit()); } return snowString.toString(); diff --git a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Weather.java b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Weather.java index 76cc009..0c3e231 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/model/weather/Weather.java +++ b/src/main/java/com/github/prominence/openweathermap/api/model/weather/Weather.java @@ -31,12 +31,9 @@ import java.util.Objects; * Represents weather information. */ public class Weather { - private String state; - private String description; - private String weatherIconId; - - private LocalDateTime calculatedOn; + private LocalDateTime calculationTime; + private WeatherState weatherState; private Temperature temperature; private AtmosphericPressure atmosphericPressure; private Humidity humidity; @@ -48,116 +45,40 @@ public class Weather { private Location location; - private Weather(String state, String description) { - this.state = state; - this.description = description; - } - - /** - * For value weather. - * - * @param state the state - * @param description the description - * @return the weather - */ - public static Weather forValue(String state, String description) { - if (state == null) { - throw new IllegalArgumentException("State must be set."); - } - if (description == null) { - throw new IllegalArgumentException("Description must be set."); - } - return new Weather(state, description); - } - - /** - * Gets state. - * - * @return the state - */ - public String getState() { - return state; - } - - /** - * Sets state. - * - * @param state the state - */ - public void setState(String state) { - if (state == null) { - throw new IllegalArgumentException("State must be set."); - } - this.state = state; - } - - /** - * Gets description. - * - * @return the description - */ - public String getDescription() { - return description; - } - - /** - * Sets description. - * - * @param description the description - */ - public void setDescription(String description) { - if (description == null) { - throw new IllegalArgumentException("Description must be set."); - } - this.description = description; - } - - /** - * Gets weather icon ID. - * - * @return the weather icon ID - */ - public String getWeatherIconId() { - return weatherIconId; - } - - /** - * Sets weather icon ID. - * - * @param weatherIconId the weather icon ID - */ - public void setWeatherIconId(String weatherIconId) { - this.weatherIconId = weatherIconId; - } - - /** - * Gets weather icon url. - * - * @return the weather icon url - */ - public String getWeatherIconUrl() { - if (weatherIconId != null) { - return "http://openweathermap.org/img/w/" + weatherIconId + ".png"; - } - return null; - } - /** * Gets calculated on. * * @return the calculated on */ - public LocalDateTime getCalculatedOn() { - return calculatedOn; + public LocalDateTime getCalculationTime() { + return calculationTime; } /** * Sets calculated on. * - * @param calculatedOn the calculated on + * @param calculationTime the calculated on */ - public void setCalculatedOn(LocalDateTime calculatedOn) { - this.calculatedOn = calculatedOn; + public void setCalculationTime(LocalDateTime calculationTime) { + this.calculationTime = calculationTime; + } + + /** + * Gets weather state. + * + * @return the weather state + */ + public WeatherState getWeatherState() { + return weatherState; + } + + /** + * Sets weather state. + * + * @param weatherState the weather state + */ + public void setWeatherState(WeatherState weatherState) { + this.weatherState = weatherState; } /** @@ -309,10 +230,8 @@ public class Weather { if (this == o) return true; if (!(o instanceof Weather)) return false; Weather weather = (Weather) o; - return Objects.equals(state, weather.state) && - Objects.equals(description, weather.description) && - Objects.equals(weatherIconId, weather.weatherIconId) && - Objects.equals(calculatedOn, weather.calculatedOn) && + return Objects.equals(calculationTime, weather.calculationTime) && + Objects.equals(weatherState, weather.weatherState) && Objects.equals(temperature, weather.temperature) && Objects.equals(atmosphericPressure, weather.atmosphericPressure) && Objects.equals(humidity, weather.humidity) && @@ -325,7 +244,7 @@ public class Weather { @Override public int hashCode() { - return Objects.hash(state, description, weatherIconId, calculatedOn, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds, location); + return Objects.hash(calculationTime, weatherState, temperature, atmosphericPressure, humidity, wind, rain, snow, clouds, location); } @Override @@ -342,8 +261,10 @@ public class Weather { stringBuilder.append(')'); } } - stringBuilder.append(", Weather: "); - stringBuilder.append(description); + if (weatherState != null) { + stringBuilder.append(", Weather: "); + stringBuilder.append(weatherState.getDescription()); + } if (temperature != null) { stringBuilder.append(", "); stringBuilder.append(temperature.getValue()); @@ -360,15 +281,15 @@ public class Weather { stringBuilder.append(", "); stringBuilder.append(clouds.toString()); } - if (rain != null && rain.getOneHourRainLevel() != null) { + if (rain != null && rain.getOneHourLevel() != null) { stringBuilder.append(", Rain: "); - stringBuilder.append(rain.getOneHourRainLevel()); + stringBuilder.append(rain.getOneHourLevel()); stringBuilder.append(' '); stringBuilder.append(rain.getUnit()); } - if (snow != null && snow.getOneHourSnowLevel() != null) { + if (snow != null && snow.getOneHourLevel() != null) { stringBuilder.append(", Snow: "); - stringBuilder.append(snow.getOneHourSnowLevel()); + stringBuilder.append(snow.getOneHourLevel()); stringBuilder.append(' '); stringBuilder.append(snow.getUnit()); } diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl.java index 9806ac7..8b333e3 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl.java @@ -33,7 +33,6 @@ import java.util.concurrent.CompletableFuture; * Async request terminator. */ public class FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl implements FiveDayThreeHourStepForecastAsyncRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizer.java index c6b10c1..1c2960b 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizer.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizer.java @@ -28,7 +28,6 @@ import com.github.prominence.openweathermap.api.request.RequestCustomizer; * The forecast request customizer interface. */ public interface FiveDayThreeHourStepForecastRequestCustomizer extends RequestCustomizer { - /** * Count customizer. * diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizerImpl.java index ec462b6..4e2fbae 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizerImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestCustomizerImpl.java @@ -30,7 +30,6 @@ import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; * The forecast request customizer. */ public class FiveDayThreeHourStepForecastRequestCustomizerImpl implements FiveDayThreeHourStepForecastRequestCustomizer { - private final RequestUrlBuilder urlBuilder; private Language language; @@ -66,15 +65,20 @@ public class FiveDayThreeHourStepForecastRequestCustomizerImpl implements FiveDa @Override public FiveDayThreeHourStepForecastRequestTerminator retrieve() { - urlBuilder.applyCustomization(language, unitSystem); - urlBuilder.addRequestParameter("cnt", count); + applyCustomization(); return new FiveDayThreeHourStepForecastRequestTerminatorImpl(urlBuilder, unitSystem); } @Override public FiveDayThreeHourStepForecastAsyncRequestTerminator retrieveAsync() { - urlBuilder.applyCustomization(language, unitSystem); - urlBuilder.addRequestParameter("cnt", count); + applyCustomization(); return new FiveDayThreeHourStepForecastAsyncRequestTerminatorImpl(urlBuilder, unitSystem); } + + private void applyCustomization() { + urlBuilder.applyCustomization(language, unitSystem); + if (count >= 0) { + urlBuilder.addRequestParameter("cnt", count); + } + } } diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestTerminatorImpl.java index 70802cd..5011467 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequestTerminatorImpl.java @@ -31,7 +31,6 @@ import com.github.prominence.openweathermap.api.utils.RequestUtils; * The forecast request terminator. */ public class FiveDayThreeHourStepForecastRequestTerminatorImpl implements FiveDayThreeHourStepForecastRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequesterImpl.java index c0479b2..b5a87f2 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequesterImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastRequesterImpl.java @@ -29,7 +29,6 @@ import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; * The forecast requester. */ public class FiveDayThreeHourStepForecastRequesterImpl implements FiveDayThreeHourStepForecastRequester { - private final RequestUrlBuilder urlBuilder; /** diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapper.java index ea07b64..b728a7c 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapper.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapper.java @@ -22,6 +22,7 @@ package com.github.prominence.openweathermap.api.request.forecast.free; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.prominence.openweathermap.api.enums.UnitSystem; @@ -32,7 +33,6 @@ import com.github.prominence.openweathermap.api.model.forecast.Rain; import com.github.prominence.openweathermap.api.model.forecast.Snow; import com.github.prominence.openweathermap.api.model.Temperature; -import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -87,7 +87,6 @@ import java.util.TimeZone; * |- city.timezone Shift in seconds from UTC */ public class FiveDayThreeHourStepForecastResponseMapper { - private final UnitSystem unitSystem; /** @@ -106,12 +105,12 @@ public class FiveDayThreeHourStepForecastResponseMapper { * @return the forecast */ public Forecast mapToForecast(String json) { - ObjectMapper objectMapper = new ObjectMapper(); + final ObjectMapper objectMapper = new ObjectMapper(); Forecast forecast; try { - JsonNode root = objectMapper.readTree(json); + final JsonNode root = objectMapper.readTree(json); forecast = mapToForecast(root); - } catch (IOException e) { + } catch (JsonProcessingException e) { throw new RuntimeException("Cannot parse Forecast response"); } @@ -119,12 +118,12 @@ public class FiveDayThreeHourStepForecastResponseMapper { } private Forecast mapToForecast(JsonNode root) { - Forecast forecast = new Forecast(); + final Forecast forecast = new Forecast(); forecast.setLocation(parseLocation(root.get("city"))); - List forecasts = new ArrayList<>(root.get("cnt").asInt()); + final List forecasts = new ArrayList<>(root.get("cnt").asInt()); - JsonNode forecastListNode = root.get("list"); + final JsonNode forecastListNode = root.get("list"); forecastListNode.forEach(forecastNode -> forecasts.add(parseWeatherForecast(forecastNode))); forecast.setWeatherForecasts(forecasts); @@ -133,14 +132,14 @@ public class FiveDayThreeHourStepForecastResponseMapper { } private WeatherForecast parseWeatherForecast(JsonNode rootNode) { - JsonNode weatherNode = rootNode.get("weather").get(0); - WeatherForecast weatherForecast = WeatherForecast.forValue( - weatherNode.get("main").asText(), - weatherNode.get("description").asText() - ); - weatherForecast.setWeatherIconId(weatherNode.get("icon").asText()); + final WeatherForecast weatherForecast = new WeatherForecast(); + final JsonNode weatherArrayNode = rootNode.get("weather"); + if (weatherArrayNode != null) { + final JsonNode weatherNode = weatherArrayNode.get(0); + weatherForecast.setWeatherState(parseWeatherState(weatherNode)); + } - JsonNode mainNode = rootNode.get("main"); + final JsonNode mainNode = rootNode.get("main"); weatherForecast.setTemperature(parseTemperature(mainNode)); weatherForecast.setAtmosphericPressure(parsePressure(mainNode)); weatherForecast.setHumidity(parseHumidity(mainNode)); @@ -149,7 +148,7 @@ public class FiveDayThreeHourStepForecastResponseMapper { weatherForecast.setRain(parseRain(rootNode)); weatherForecast.setSnow(parseSnow(rootNode)); - JsonNode sysNode = rootNode.get("sys"); + final JsonNode sysNode = rootNode.get("sys"); if (sysNode != null) { weatherForecast.setDayTime("d".equals(sysNode.get("pod").asText()) ? DayTime.DAY : DayTime.NIGHT); } @@ -160,9 +159,23 @@ public class FiveDayThreeHourStepForecastResponseMapper { return weatherForecast; } + private WeatherState parseWeatherState(JsonNode weatherNode) { + if (weatherNode == null) { + return null; + } + final WeatherState weatherState = new WeatherState( + weatherNode.get("id").asInt(), + weatherNode.get("main").asText(), + weatherNode.get("description").asText() + ); + weatherState.setIconId(weatherNode.get("icon").asText()); + + return weatherState; + } + private Temperature parseTemperature(JsonNode rootNode) { final double tempValue = rootNode.get("temp").asDouble(); - Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit()); + final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit()); final JsonNode tempMaxNode = rootNode.get("temp_max"); if (tempMaxNode != null) { @@ -172,7 +185,7 @@ public class FiveDayThreeHourStepForecastResponseMapper { if (tempMinNode != null) { temperature.setMinTemperature(tempMinNode.asDouble()); } - final JsonNode tempFeelsLike = rootNode.get("fells_like"); + final JsonNode tempFeelsLike = rootNode.get("feels_like"); if (tempFeelsLike != null) { temperature.setFeelsLike(tempFeelsLike.asDouble()); } @@ -181,7 +194,7 @@ public class FiveDayThreeHourStepForecastResponseMapper { } private AtmosphericPressure parsePressure(JsonNode rootNode) { - AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(rootNode.get("pressure").asDouble()); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(rootNode.get("pressure").asDouble()); final JsonNode seaLevelNode = rootNode.get("sea_level"); final JsonNode groundLevelNode = rootNode.get("grnd_level"); @@ -203,7 +216,7 @@ public class FiveDayThreeHourStepForecastResponseMapper { final JsonNode windNode = root.get("wind"); double speed = windNode.get("speed").asDouble(); - Wind wind = Wind.withValue(speed, unitSystem.getWindUnit()); + final Wind wind = Wind.withValue(speed, unitSystem.getWindUnit()); final JsonNode degNode = windNode.get("deg"); if (degNode != null) { wind.setDegrees(degNode.asDouble()); @@ -228,26 +241,24 @@ public class FiveDayThreeHourStepForecastResponseMapper { if (snowNode != null) { final JsonNode threeHourNode = snowNode.get("3h"); if (threeHourNode != null) { - Rain.withThreeHourLevelValue(threeHourNode.asDouble()); + return Snow.withThreeHourLevelValue(threeHourNode.asDouble()); } } return null; } private Clouds parseClouds(JsonNode rootNode) { - Clouds clouds = null; - final JsonNode cloudsNode = rootNode.get("clouds"); final JsonNode allValueNode = cloudsNode.get("all"); if (allValueNode != null) { - clouds = Clouds.withValue((byte) allValueNode.asInt()); + return Clouds.withValue((byte) allValueNode.asInt()); } - return clouds; + return null; } private Location parseLocation(JsonNode rootNode) { - Location location = Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText()); + final Location location = Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText()); final JsonNode timezoneNode = rootNode.get("timezone"); if (timezoneNode != null) { @@ -262,10 +273,10 @@ public class FiveDayThreeHourStepForecastResponseMapper { final JsonNode sunriseNode = rootNode.get("sunrise"); final JsonNode sunsetNode = rootNode.get("sunset"); if (sunriseNode != null) { - location.setSunrise(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asLong()), TimeZone.getDefault().toZoneId())); + location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asLong()), TimeZone.getDefault().toZoneId())); } if (sunsetNode != null) { - location.setSunset(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asLong()), TimeZone.getDefault().toZoneId())); + location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asLong()), TimeZone.getDefault().toZoneId())); } final JsonNode coordNode = rootNode.get("coord"); @@ -282,10 +293,10 @@ public class FiveDayThreeHourStepForecastResponseMapper { } private Coordinate parseCoordinate(JsonNode rootNode) { - JsonNode latitudeNode = rootNode.get("lat"); - JsonNode longitudeNode = rootNode.get("lon"); + final JsonNode latitudeNode = rootNode.get("lat"); + final JsonNode longitudeNode = rootNode.get("lon"); if (latitudeNode != null && longitudeNode != null) { - return Coordinate.withValues(latitudeNode.asDouble(), longitudeNode.asDouble()); + return Coordinate.of(latitudeNode.asDouble(), longitudeNode.asDouble()); } return null; } diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequester.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequester.java new file mode 100644 index 0000000..2b58177 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequester.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall; + +import com.github.prominence.openweathermap.api.request.onecall.current.OneCallCurrentWeatherRequester; +import com.github.prominence.openweathermap.api.request.onecall.historical.OneCallHistoricalWeatherRequester; + +/** + * The interface One call weather requester. + */ +public interface OneCallWeatherRequester { + /** + * Current one call current weather requester. + * + * @return the one call current weather requester + */ + OneCallCurrentWeatherRequester current(); + + /** + * Historical one call historical weather requester. + * + * @return the one call historical weather requester + */ + OneCallHistoricalWeatherRequester historical(); +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequesterImpl.java new file mode 100644 index 0000000..d0dddb1 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherRequesterImpl.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall; + +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; +import com.github.prominence.openweathermap.api.request.onecall.current.OneCallCurrentWeatherRequester; +import com.github.prominence.openweathermap.api.request.onecall.current.OneCallCurrentWeatherRequesterImpl; +import com.github.prominence.openweathermap.api.request.onecall.historical.OneCallHistoricalWeatherRequester; +import com.github.prominence.openweathermap.api.request.onecall.historical.OneCallHistoricalWeatherRequesterImpl; + +/** + * The type One call weather requester. + */ +public class OneCallWeatherRequesterImpl implements OneCallWeatherRequester { + private final RequestUrlBuilder urlBuilder; + + /** + * Instantiates a new One call weather requester. + * + * @param apiKey the api key + */ + public OneCallWeatherRequesterImpl(String apiKey) { + urlBuilder = new RequestUrlBuilder(apiKey); + } + + @Override + public OneCallCurrentWeatherRequester current() { + return new OneCallCurrentWeatherRequesterImpl(urlBuilder); + } + + @Override + public OneCallHistoricalWeatherRequester historical() { + return new OneCallHistoricalWeatherRequesterImpl(urlBuilder); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapper.java new file mode 100644 index 0000000..5b4caf3 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapper.java @@ -0,0 +1,430 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; +import com.github.prominence.openweathermap.api.model.onecall.current.*; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeather; +import com.github.prominence.openweathermap.api.model.onecall.historical.HourlyHistorical; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; + +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; +import java.util.TimeZone; + +/** + * Object mapper for OneCall API response. + */ +public class OneCallWeatherResponseMapper { + private final UnitSystem unitSystem; + + /** + * Instantiates a new forecast response mapper. + * + * @param unitSystem the unit system + */ + public OneCallWeatherResponseMapper(UnitSystem unitSystem) { + this.unitSystem = unitSystem; + } + + /** + * Maps current weather data response into java object. + * + * @param json the json string + * @return the current data object + */ + public CurrentWeatherData mapToCurrent(String json) { + final ObjectMapper objectMapper = new ObjectMapper(); + CurrentWeatherData currentData; + try { + final JsonNode root = objectMapper.readTree(json); + currentData = mapToCurrent(root); + } catch (JsonProcessingException e) { + throw new RuntimeException("Cannot parse Forecast response"); + } + + return currentData; + } + + /** + * Maps current weather data response into java object. + * + * @param json the json string + * @return the current data object + */ + public HistoricalWeatherData mapToHistorical(String json) { + final ObjectMapper objectMapper = new ObjectMapper(); + HistoricalWeatherData historicalData; + try { + final JsonNode root = objectMapper.readTree(json); + historicalData = mapToHistorical(root); + } catch (JsonProcessingException e) { + throw new RuntimeException("Cannot parse Forecast response"); + } + + return historicalData; + } + + private CurrentWeatherData mapToCurrent(JsonNode rootNode) { + final CurrentWeatherData currentData = new CurrentWeatherData(); + currentData.setCoordinate(Coordinate.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble())); + currentData.setTimezone(ZoneId.of(rootNode.get("timezone").asText())); + currentData.setTimezoneOffset(ZoneOffset.ofTotalSeconds(rootNode.get("timezone_offset").asInt())); + currentData.setCurrent(parseCurrent(rootNode.get("current"))); + currentData.setMinutelyList(parseMinutelyList(rootNode.get("minutely"))); + currentData.setHourlyList(parseHourlyList(rootNode.get("hourly"))); + currentData.setDailyList(parseDailyList(rootNode.get("daily"))); + currentData.setAlerts(parseAlerts(rootNode.get("alerts"))); + + return currentData; + } + + private Current parseCurrent(JsonNode currentNode) { + if (currentNode == null) { + return null; + } + final Current current = new Current(); + current.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); + current.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); + current.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); + + current.setWeatherState(parseWeatherState(currentNode.get("weather").get(0))); + current.setTemperature(parseTemperature(currentNode)); + current.setAtmosphericPressure(parsePressure(currentNode)); + current.setHumidity(parseHumidity(currentNode)); + current.setClouds(parseClouds(currentNode)); + current.setUvIndex(currentNode.get("uvi").asDouble()); + final JsonNode visibilityNode = currentNode.get("visibility"); + if (visibilityNode != null) { + current.setVisibilityInMetres(visibilityNode.asDouble()); + } + current.setWind(parseWind(currentNode)); + current.setRain(parseRain(currentNode)); + current.setSnow(parseSnow(currentNode)); + + return current; + } + + private List parseMinutelyList(JsonNode minutelyListNode) { + if (minutelyListNode == null) { + return null; + } + final List minutelyList = new ArrayList<>(); + for (final JsonNode minutelyNode : minutelyListNode) { + minutelyList.add(Minutely.withValue( + LocalDateTime.ofInstant(Instant.ofEpochSecond(minutelyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId()), + minutelyNode.get("precipitation").asDouble() + )); + } + + return minutelyList; + } + + private List parseHourlyList(JsonNode hourlyListNode) { + if (hourlyListNode == null) { + return null; + } + final List hourlyList = new ArrayList<>(); + for (final JsonNode hourlyNode : hourlyListNode) { + final Hourly hourly = new Hourly(); + hourly.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(hourlyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); + + hourly.setWeatherState(parseWeatherState(hourlyNode.get("weather").get(0))); + hourly.setTemperature(parseTemperature(hourlyNode)); + hourly.setAtmosphericPressure(parsePressure(hourlyNode)); + hourly.setHumidity(parseHumidity(hourlyNode)); + hourly.setClouds(parseClouds(hourlyNode)); + + final JsonNode uviNode = hourlyNode.get("uvi"); + if (uviNode != null) { + hourly.setUvIndex(uviNode.asDouble()); + } + + final JsonNode visibilityNode = hourlyNode.get("visibility"); + if (visibilityNode != null) { + hourly.setVisibilityInMetres(visibilityNode.asDouble()); + } + hourly.setWind(parseWind(hourlyNode)); + final JsonNode popNode = hourlyNode.get("pop"); + if (popNode != null) { + hourly.setProbabilityOfPrecipitation(popNode.asDouble()); + } + hourly.setRain(parseRain(hourlyNode)); + hourly.setSnow(parseSnow(hourlyNode)); + + hourlyList.add(hourly); + } + + return hourlyList; + } + + private List parseDailyList(JsonNode dailyListNode) { + if (dailyListNode == null) { + return null; + } + final List dailyList = new ArrayList<>(); + for (final JsonNode dailyNode : dailyListNode) { + final Daily daily = new Daily(); + daily.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); + daily.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); + daily.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dailyNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); + + daily.setWeatherState(parseWeatherState(dailyNode.get("weather").get(0))); + daily.setTemperature(parseDailyTemperature(dailyNode)); + daily.setAtmosphericPressure(parsePressure(dailyNode)); + daily.setHumidity(parseHumidity(dailyNode)); + daily.setWind(parseWind(dailyNode)); + daily.setClouds(parseClouds(dailyNode)); + daily.setUvIndex(dailyNode.get("uvi").asDouble()); + daily.setProbabilityOfPrecipitation(dailyNode.get("pop").asDouble()); + daily.setRain(parseDailyRain(dailyNode)); + daily.setSnow(parseDailySnow(dailyNode)); + + dailyList.add(daily); + } + + return dailyList; + } + + private List parseAlerts(JsonNode alertsNode) { + if (alertsNode == null) { + return null; + } + final List alerts = new ArrayList<>(); + for (final JsonNode alertNode : alertsNode) { + Alert alert = new Alert(); + alert.setSenderName(alertNode.get("sender_name").asText()); + alert.setEventName(alertNode.get("event").asText()); + alert.setStartTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(alertNode.get("start").asInt()), TimeZone.getDefault().toZoneId())); + alert.setEndTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(alertNode.get("end").asInt()), TimeZone.getDefault().toZoneId())); + alert.setDescription(alertNode.get("description").asText()); + alerts.add(alert); + } + return alerts; + } + + private HistoricalWeatherData mapToHistorical(JsonNode rootNode) { + final HistoricalWeatherData historicalData = new HistoricalWeatherData(); + historicalData.setCoordinate(Coordinate.of(rootNode.get("lat").asDouble(), rootNode.get("lon").asDouble())); + historicalData.setTimezone(ZoneId.of(rootNode.get("timezone").asText())); + historicalData.setTimezoneOffset(ZoneOffset.ofTotalSeconds(rootNode.get("timezone_offset").asInt())); + historicalData.setHistoricalWeather(parseHistoricalWeather(rootNode.get("current"))); + historicalData.setHourlyList(parseHourlyHistoricalList(rootNode.get("hourly"))); + + return historicalData; + } + + private HistoricalWeather parseHistoricalWeather(JsonNode currentNode) { + if (currentNode == null) { + return null; + } + final HistoricalWeather historicalWeather = new HistoricalWeather(); + historicalWeather.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); + historicalWeather.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunrise").asInt()), TimeZone.getDefault().toZoneId())); + historicalWeather.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(currentNode.get("sunset").asInt()), TimeZone.getDefault().toZoneId())); + + final JsonNode weatherListNode = currentNode.get("weather"); + if (weatherListNode != null) { + historicalWeather.setWeatherState(parseWeatherState(weatherListNode.get(0))); + } + historicalWeather.setTemperature(parseTemperature(currentNode)); + historicalWeather.setAtmosphericPressure(parsePressure(currentNode)); + historicalWeather.setHumidity(parseHumidity(currentNode)); + historicalWeather.setClouds(parseClouds(currentNode)); + historicalWeather.setUvIndex(currentNode.get("uvi").asDouble()); + final JsonNode visibilityMode = currentNode.get("visibility"); + if (visibilityMode != null) { + historicalWeather.setVisibilityInMetres(visibilityMode.asDouble()); + } + historicalWeather.setWind(parseWind(currentNode)); + historicalWeather.setRain(parseRain(currentNode)); + historicalWeather.setSnow(parseSnow(currentNode)); + + return historicalWeather; + } + + private List parseHourlyHistoricalList(JsonNode hourlyListNode) { + if (hourlyListNode == null) { + return null; + } + final List hourlyList = new ArrayList<>(); + for (final JsonNode hourlyNode : hourlyListNode) { + final HourlyHistorical hourly = new HourlyHistorical(); + hourly.setForecastTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(hourlyNode.get("dt").asInt()), TimeZone.getDefault().toZoneId())); + + hourly.setWeatherState(parseWeatherState(hourlyNode.get("weather").get(0))); + hourly.setTemperature(parseTemperature(hourlyNode)); + hourly.setAtmosphericPressure(parsePressure(hourlyNode)); + hourly.setHumidity(parseHumidity(hourlyNode)); + hourly.setClouds(parseClouds(hourlyNode)); + + final JsonNode visibilityNode = hourlyNode.get("visibility"); + if (visibilityNode != null) { + hourly.setVisibilityInMetres(visibilityNode.asDouble()); + } + hourly.setWind(parseWind(hourlyNode)); + hourly.setRain(parseRain(hourlyNode)); + hourly.setSnow(parseSnow(hourlyNode)); + + hourlyList.add(hourly); + } + + return hourlyList; + } + + private WeatherState parseWeatherState(JsonNode weatherNode) { + if (weatherNode == null) { + return null; + } + final WeatherState weatherState = new WeatherState( + weatherNode.get("id").asInt(), + weatherNode.get("main").asText(), + weatherNode.get("description").asText() + ); + weatherState.setIconId(weatherNode.get("icon").asText()); + + return weatherState; + } + + private Temperature parseTemperature(JsonNode rootNode) { + final double tempValue = rootNode.get("temp").asDouble(); + final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit()); + + final JsonNode tempFeelsLike = rootNode.get("feels_like"); + if (tempFeelsLike != null) { + temperature.setFeelsLike(tempFeelsLike.asDouble()); + } + final JsonNode dewPoint = rootNode.get("dew_point"); + if (dewPoint != null) { + temperature.setDewPoint(dewPoint.asDouble()); + } + + return temperature; + } + + private DailyTemperature parseDailyTemperature(JsonNode dailyNode) { + final DailyTemperature temperature = new DailyTemperature(); + final JsonNode tempNode = dailyNode.get("temp"); + temperature.setMorning(tempNode.get("morn").asDouble()); + temperature.setDay(tempNode.get("day").asDouble()); + temperature.setEve(tempNode.get("eve").asDouble()); + temperature.setNight(tempNode.get("night").asDouble()); + temperature.setMin(tempNode.get("min").asDouble()); + temperature.setMax(tempNode.get("max").asDouble()); + + final JsonNode feelsLikeNode = dailyNode.get("feels_like"); + temperature.setMorningFeelsLike(feelsLikeNode.get("morn").asDouble()); + temperature.setDayFeelsLike(feelsLikeNode.get("day").asDouble()); + temperature.setEveFeelsLike(feelsLikeNode.get("eve").asDouble()); + temperature.setNightFeelsLike(feelsLikeNode.get("night").asDouble()); + + return temperature; + } + + private AtmosphericPressure parsePressure(JsonNode rootNode) { + return AtmosphericPressure.withValue(rootNode.get("pressure").asDouble()); + } + + private Humidity parseHumidity(JsonNode rootNode) { + return Humidity.withValue((byte) (rootNode.get("humidity").asInt())); + } + + private Wind parseWind(JsonNode rootNode) { + final JsonNode windSpeedNode = rootNode.get("wind_speed"); + if (windSpeedNode == null) { + return null; + } + + final Wind wind = Wind.withValue(windSpeedNode.asDouble(), unitSystem.getWindUnit()); + + final JsonNode degNode = rootNode.get("wind_deg"); + if (degNode != null) { + wind.setDegrees(degNode.asDouble()); + } + final JsonNode gustNode = rootNode.get("wind_gust"); + if (gustNode != null) { + wind.setGust(gustNode.asDouble()); + } + + return wind; + } + + private Rain parseRain(JsonNode root) { + final JsonNode rainNode = root.get("rain"); + if (rainNode != null) { + final JsonNode oneHourNode = rainNode.get("1h"); + if (oneHourNode != null) { + return Rain.withOneHourLevelValue(oneHourNode.asDouble()); + } + } + return null; + } + + private DailyRain parseDailyRain(JsonNode dailyNode) { + final JsonNode valueNode = dailyNode.get("rain"); + if (valueNode != null) { + return DailyRain.withValue(valueNode.asDouble()); + } + return null; + } + + private Snow parseSnow(JsonNode root) { + final JsonNode snowNode = root.get("snow"); + if (snowNode != null) { + final JsonNode OneHourNode = snowNode.get("1h"); + if (OneHourNode != null) { + Rain.withOneHourLevelValue(OneHourNode.asDouble()); + } + } + return null; + } + + private DailySnow parseDailySnow(JsonNode dailyNode) { + final JsonNode valueNode = dailyNode.get("snow"); + if (valueNode != null) { + return DailySnow.withValue(valueNode.asDouble()); + } + return null; + } + + private Clouds parseClouds(JsonNode rootNode) { + final JsonNode cloudsNode = rootNode.get("clouds"); + if (cloudsNode != null) { + return Clouds.withValue((byte) cloudsNode.asInt()); + } + + return null; + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminator.java new file mode 100644 index 0000000..63811e5 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminator.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import com.github.prominence.openweathermap.api.request.AsyncRequestTerminator; + +/** + * The interface One call current weather async request terminator. + */ +public interface OneCallCurrentWeatherAsyncRequestTerminator extends AsyncRequestTerminator { +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminatorImpl.java new file mode 100644 index 0000000..da2dd81 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherAsyncRequestTerminatorImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherResponseMapper; +import com.github.prominence.openweathermap.api.utils.RequestUtils; + +import java.util.concurrent.CompletableFuture; + +/** + * The type One call current weather async request terminator. + */ +public class OneCallCurrentWeatherAsyncRequestTerminatorImpl implements OneCallCurrentWeatherAsyncRequestTerminator { + private final RequestUrlBuilder urlBuilder; + private final UnitSystem unitSystem; + + /** + * Instantiates a new One call current weather async request terminator. + * + * @param urlBuilder the url builder + * @param unitSystem the unit system + */ + OneCallCurrentWeatherAsyncRequestTerminatorImpl(RequestUrlBuilder urlBuilder, UnitSystem unitSystem) { + this.urlBuilder = urlBuilder; + this.unitSystem = unitSystem; + } + + @Override + public CompletableFuture asJava() { + return CompletableFuture.supplyAsync(() -> new OneCallWeatherResponseMapper(unitSystem).mapToCurrent(getRawResponse())); + } + + @Override + public CompletableFuture asJSON() { + return CompletableFuture.supplyAsync(this::getRawResponse); + } + + private String getRawResponse() { + return RequestUtils.getResponse(urlBuilder.buildUrl()); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizer.java new file mode 100644 index 0000000..33143c4 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizer.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.enums.OneCallResultOptions; +import com.github.prominence.openweathermap.api.request.RequestCustomizer; + +/** + * The interface One call current weather request customizer. + */ +public interface OneCallCurrentWeatherRequestCustomizer extends RequestCustomizer { + /** + * Exclude one call current weather request customizer. + * + * @param excludeOptions the exclude options + * @return the one call current weather request customizer + */ + OneCallCurrentWeatherRequestCustomizer exclude(OneCallResultOptions... excludeOptions); + + /** + * Retrieve one call current weather request terminator. + * + * @return the one call current weather request terminator + */ + OneCallCurrentWeatherRequestTerminator retrieve(); + + /** + * Retrieve async one call current weather async request terminator. + * + * @return the one call current weather async request terminator + */ + OneCallCurrentWeatherAsyncRequestTerminator retrieveAsync(); +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizerImpl.java new file mode 100644 index 0000000..a55636a --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestCustomizerImpl.java @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.enums.Language; +import com.github.prominence.openweathermap.api.enums.OneCallResultOptions; +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; + +import java.util.stream.Collectors; +import java.util.stream.Stream; + +/** + * The type One call current weather request customizer. + */ +public class OneCallCurrentWeatherRequestCustomizerImpl implements OneCallCurrentWeatherRequestCustomizer { + private final RequestUrlBuilder urlBuilder; + + private Language language; + private UnitSystem unitSystem = UnitSystem.STANDARD; + private OneCallResultOptions[] excludeOptions; + + /** + * Instantiates a new One call current weather request customizer. + * + * @param urlBuilder the url builder + */ + OneCallCurrentWeatherRequestCustomizerImpl(RequestUrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + } + + @Override + public OneCallCurrentWeatherRequestCustomizer language(Language language) { + this.language = language; + return this; + } + + @Override + public OneCallCurrentWeatherRequestCustomizer unitSystem(UnitSystem unitSystem) { + this.unitSystem = unitSystem; + return this; + } + + @Override + public OneCallCurrentWeatherRequestCustomizer exclude(OneCallResultOptions... excludeOptions) { + this.excludeOptions = excludeOptions; + return this; + } + + @Override + public OneCallCurrentWeatherRequestTerminator retrieve() { + applyCustomization(); + return new OneCallCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); + } + + @Override + public OneCallCurrentWeatherAsyncRequestTerminator retrieveAsync() { + applyCustomization(); + return new OneCallCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); + } + + private void applyCustomization() { + urlBuilder.applyCustomization(language, unitSystem); + if (excludeOptions != null) { + urlBuilder.addRequestParameter("exclude", Stream.of(excludeOptions).map(OneCallResultOptions::getValue).collect(Collectors.joining(","))); + } + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminator.java new file mode 100644 index 0000000..a23d3b1 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminator.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import com.github.prominence.openweathermap.api.request.RequestTerminator; + +/** + * The interface One call current weather request terminator. + */ +public interface OneCallCurrentWeatherRequestTerminator extends RequestTerminator { + +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminatorImpl.java new file mode 100644 index 0000000..a2ea7c7 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequestTerminatorImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherResponseMapper; +import com.github.prominence.openweathermap.api.utils.RequestUtils; + +/** + * The type One call current weather request terminator. + */ +public class OneCallCurrentWeatherRequestTerminatorImpl implements OneCallCurrentWeatherRequestTerminator { + private final RequestUrlBuilder urlBuilder; + private final UnitSystem unitSystem; + + /** + * Instantiates a new One call current weather request terminator. + * + * @param urlBuilder the url builder + * @param unitSystem the unit system + */ + OneCallCurrentWeatherRequestTerminatorImpl(RequestUrlBuilder urlBuilder, UnitSystem unitSystem) { + this.urlBuilder = urlBuilder; + this.unitSystem = unitSystem; + } + + @Override + public CurrentWeatherData asJava() { + return new OneCallWeatherResponseMapper(unitSystem).mapToCurrent(getRawResponse()); + } + + @Override + public String asJSON() { + return getRawResponse(); + } + + private String getRawResponse() { + return RequestUtils.getResponse(urlBuilder.buildUrl()); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequester.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequester.java new file mode 100644 index 0000000..edc40ec --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequester.java @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.model.Coordinate; + +/** + * The interface One call current weather requester. + */ +public interface OneCallCurrentWeatherRequester { + /** + * By coordinate one call current weather request customizer. + * + * @param coordinate the coordinate + * @return the one call current weather request customizer + */ + OneCallCurrentWeatherRequestCustomizer byCoordinate(Coordinate coordinate); +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequesterImpl.java new file mode 100644 index 0000000..3da0121 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/current/OneCallCurrentWeatherRequesterImpl.java @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; + +/** + * The type One call current weather requester. + */ +public class OneCallCurrentWeatherRequesterImpl implements OneCallCurrentWeatherRequester { + private final RequestUrlBuilder urlBuilder; + + /** + * Instantiates a new One call current weather requester. + * + * @param urlBuilder the url builder + */ + public OneCallCurrentWeatherRequesterImpl(RequestUrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + urlBuilder.append("onecall"); + } + + @Override + public OneCallCurrentWeatherRequestCustomizer byCoordinate(Coordinate coordinate) { + urlBuilder.addRequestParameter("lat", String.valueOf(coordinate.getLatitude())); + urlBuilder.addRequestParameter("lon", String.valueOf(coordinate.getLongitude())); + return new OneCallCurrentWeatherRequestCustomizerImpl(urlBuilder); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminator.java new file mode 100644 index 0000000..7984522 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminator.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import com.github.prominence.openweathermap.api.request.AsyncRequestTerminator; + +/** + * The interface One call historical weather async request terminator. + */ +public interface OneCallHistoricalWeatherAsyncRequestTerminator extends AsyncRequestTerminator { +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminatorImpl.java new file mode 100644 index 0000000..e2dc671 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherAsyncRequestTerminatorImpl.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherResponseMapper; +import com.github.prominence.openweathermap.api.utils.RequestUtils; + +import java.util.concurrent.CompletableFuture; + +/** + * The type One call historical weather async request terminator. + */ +public class OneCallHistoricalWeatherAsyncRequestTerminatorImpl implements OneCallHistoricalWeatherAsyncRequestTerminator { + private final RequestUrlBuilder urlBuilder; + private final UnitSystem unitSystem; + + /** + * Instantiates a new One call historical weather async request terminator. + * + * @param urlBuilder the url builder + * @param unitSystem the unit system + */ + public OneCallHistoricalWeatherAsyncRequestTerminatorImpl(RequestUrlBuilder urlBuilder, UnitSystem unitSystem) { + this.urlBuilder = urlBuilder; + this.unitSystem = unitSystem; + } + + @Override + public CompletableFuture asJava() { + return CompletableFuture.supplyAsync(() -> new OneCallWeatherResponseMapper(unitSystem).mapToHistorical(getRawResponse())); + } + + @Override + public CompletableFuture asJSON() { + return CompletableFuture.supplyAsync(this::getRawResponse); + } + + private String getRawResponse() { + return RequestUtils.getResponse(urlBuilder.buildUrl()); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizer.java new file mode 100644 index 0000000..57ce89f --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizer.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.request.RequestCustomizer; + +/** + * The interface One call historical weather request customizer. + */ +public interface OneCallHistoricalWeatherRequestCustomizer extends RequestCustomizer { + /** + * Retrieve one call historical weather request terminator. + * + * @return the one call historical weather request terminator + */ + OneCallHistoricalWeatherRequestTerminator retrieve(); + + /** + * Retrieve async one call historical weather async request terminator. + * + * @return the one call historical weather async request terminator + */ + OneCallHistoricalWeatherAsyncRequestTerminator retrieveAsync(); +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizerImpl.java new file mode 100644 index 0000000..f6b109f --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestCustomizerImpl.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.enums.Language; +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; + +/** + * The type One call historical weather request customizer. + */ +public class OneCallHistoricalWeatherRequestCustomizerImpl implements OneCallHistoricalWeatherRequestCustomizer { + private final RequestUrlBuilder urlBuilder; + + private Language language; + private UnitSystem unitSystem = UnitSystem.STANDARD; + + /** + * Instantiates a new One call historical weather request customizer. + * + * @param urlBuilder the url builder + */ + public OneCallHistoricalWeatherRequestCustomizerImpl(RequestUrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + } + + @Override + public OneCallHistoricalWeatherRequestCustomizer language(Language language) { + this.language = language; + return this; + } + + @Override + public OneCallHistoricalWeatherRequestCustomizer unitSystem(UnitSystem unitSystem) { + this.unitSystem = unitSystem; + return this; + } + + @Override + public OneCallHistoricalWeatherRequestTerminator retrieve() { + urlBuilder.applyCustomization(language, unitSystem); + return new OneCallHistoricalWeatherRequestTerminatorImpl(urlBuilder, unitSystem); + } + + @Override + public OneCallHistoricalWeatherAsyncRequestTerminator retrieveAsync() { + urlBuilder.applyCustomization(language, unitSystem); + return new OneCallHistoricalWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminator.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminator.java new file mode 100644 index 0000000..5ab6405 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminator.java @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import com.github.prominence.openweathermap.api.request.RequestTerminator; + +/** + * The interface One call historical weather request terminator. + */ +public interface OneCallHistoricalWeatherRequestTerminator extends RequestTerminator { +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminatorImpl.java new file mode 100644 index 0000000..56a6c72 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequestTerminatorImpl.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; +import com.github.prominence.openweathermap.api.request.onecall.OneCallWeatherResponseMapper; +import com.github.prominence.openweathermap.api.utils.RequestUtils; + +/** + * The type One call historical weather request terminator. + */ +public class OneCallHistoricalWeatherRequestTerminatorImpl implements OneCallHistoricalWeatherRequestTerminator { + private final RequestUrlBuilder urlBuilder; + private final UnitSystem unitSystem; + + /** + * Instantiates a new One call historical weather request terminator. + * + * @param urlBuilder the url builder + * @param unitSystem the unit system + */ + public OneCallHistoricalWeatherRequestTerminatorImpl(RequestUrlBuilder urlBuilder, UnitSystem unitSystem) { + this.urlBuilder = urlBuilder; + this.unitSystem = unitSystem; + } + + @Override + public HistoricalWeatherData asJava() { + return new OneCallWeatherResponseMapper(unitSystem).mapToHistorical(getRawResponse()); + } + + @Override + public String asJSON() { + return getRawResponse(); + } + + private String getRawResponse() { + return RequestUtils.getResponse(urlBuilder.buildUrl()); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequester.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequester.java new file mode 100644 index 0000000..6cb4849 --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequester.java @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Coordinate; + +/** + * The interface One call historical weather requester. + */ +public interface OneCallHistoricalWeatherRequester { + /** + * By coordinate and timestamp one call historical weather request customizer. + * + * @param coordinate the coordinate + * @param unixTime the unix time + * @return the one call historical weather request customizer + */ + OneCallHistoricalWeatherRequestCustomizer byCoordinateAndTimestamp(Coordinate coordinate, long unixTime); +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequesterImpl.java new file mode 100644 index 0000000..928b46a --- /dev/null +++ b/src/main/java/com/github/prominence/openweathermap/api/request/onecall/historical/OneCallHistoricalWeatherRequesterImpl.java @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; + +/** + * The type One call historical weather requester. + */ +public class OneCallHistoricalWeatherRequesterImpl implements OneCallHistoricalWeatherRequester { + private final RequestUrlBuilder urlBuilder; + + /** + * Instantiates a new One call historical weather requester. + * + * @param urlBuilder the url builder + */ + public OneCallHistoricalWeatherRequesterImpl(RequestUrlBuilder urlBuilder) { + this.urlBuilder = urlBuilder; + urlBuilder.append("onecall/timemachine"); + } + + @Override + public OneCallHistoricalWeatherRequestCustomizer byCoordinateAndTimestamp(Coordinate coordinate, long unixTime) { + urlBuilder.addRequestParameter("lat", coordinate.getLatitude()); + urlBuilder.addRequestParameter("lon", coordinate.getLongitude()); + urlBuilder.addRequestParameter("dt", unixTime); + return new OneCallHistoricalWeatherRequestCustomizerImpl(urlBuilder); + } +} diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequesterImpl.java index b3b0811..0b393d6 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequesterImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherRequesterImpl.java @@ -32,7 +32,6 @@ import com.github.prominence.openweathermap.api.request.weather.single.SingleLoc * The type Current weather requester. */ public class CurrentWeatherRequesterImpl implements CurrentWeatherRequester { - private final RequestUrlBuilder urlBuilder; /** diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapper.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapper.java index 67b8477..be74bee 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapper.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapper.java @@ -22,13 +22,13 @@ package com.github.prominence.openweathermap.api.request.weather; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.github.prominence.openweathermap.api.model.weather.*; import com.github.prominence.openweathermap.api.enums.UnitSystem; import com.github.prominence.openweathermap.api.model.*; -import java.io.IOException; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneOffset; @@ -83,7 +83,6 @@ import java.util.TimeZone; * --- cod Internal parameter */ public class CurrentWeatherResponseMapper { - private final UnitSystem unitSystem; /** @@ -102,12 +101,12 @@ public class CurrentWeatherResponseMapper { * @return the weather object */ public Weather getSingle(String json) { - ObjectMapper objectMapper = new ObjectMapper(); + final ObjectMapper objectMapper = new ObjectMapper(); Weather weather; try { - JsonNode root = objectMapper.readTree(json); + final JsonNode root = objectMapper.readTree(json); weather = getSingle(root); - } catch (IOException e) { + } catch (JsonProcessingException e) { throw new RuntimeException("Cannot parse Weather response"); } @@ -115,10 +114,11 @@ public class CurrentWeatherResponseMapper { } private Weather getSingle(JsonNode rootNode) { - JsonNode weatherState = rootNode.get("weather").get(0); - Weather weather = Weather.forValue(weatherState.get("main").asText(), weatherState.get("description").asText()); - weather.setWeatherIconId(weatherState.get("icon").asText()); + final JsonNode weatherArrayNode = rootNode.get("weather"); + final JsonNode weatherNode = weatherArrayNode != null ? weatherArrayNode.get(0) : null; + final Weather weather = new Weather(); + weather.setWeatherState(parseWeatherState(weatherNode)); weather.setTemperature(parseTemperature(rootNode)); weather.setAtmosphericPressure(parsePressure(rootNode)); weather.setHumidity(parseHumidity(rootNode)); @@ -130,7 +130,7 @@ public class CurrentWeatherResponseMapper { final JsonNode dtNode = rootNode.get("dt"); if (dtNode != null) { - weather.setCalculatedOn(LocalDateTime.ofInstant(Instant.ofEpochSecond(dtNode.asInt()), TimeZone.getDefault().toZoneId())); + weather.setCalculationTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(dtNode.asInt()), TimeZone.getDefault().toZoneId())); } return weather; @@ -143,25 +143,37 @@ public class CurrentWeatherResponseMapper { * @return the list of weathers */ public List getList(String json) { - ObjectMapper objectMapper = new ObjectMapper(); - List weatherList = new ArrayList<>(); + final ObjectMapper objectMapper = new ObjectMapper(); + final List weatherList = new ArrayList<>(); try { final JsonNode root = objectMapper.readTree(json); final JsonNode listNode = root.get("list"); listNode.forEach(jsonNode -> weatherList.add(getSingle(jsonNode))); - } catch (IOException e) { + } catch (JsonProcessingException e) { throw new RuntimeException("Cannot parse Weather response"); } return weatherList; } - private Temperature parseTemperature(JsonNode rootNode) { - Temperature temperature; - final JsonNode mainNode = rootNode.get("main"); + private WeatherState parseWeatherState(JsonNode weatherNode) { + if (weatherNode == null) { + return null; + } + final WeatherState weatherState = new WeatherState( + weatherNode.get("id").asInt(), + weatherNode.get("main").asText(), + weatherNode.get("description").asText() + ); + weatherState.setIconId(weatherNode.get("icon").asText()); + return weatherState; + } + + private Temperature parseTemperature(JsonNode rootNode) { + final JsonNode mainNode = rootNode.get("main"); final double tempValue = mainNode.get("temp").asDouble(); - temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit()); + final Temperature temperature = Temperature.withValue(tempValue, unitSystem.getTemperatureUnit()); final JsonNode feelsLikeNode = mainNode.get("feels_like"); if (feelsLikeNode != null) { @@ -181,7 +193,7 @@ public class CurrentWeatherResponseMapper { private AtmosphericPressure parsePressure(JsonNode rootNode) { final JsonNode mainNode = rootNode.get("main"); - AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(mainNode.get("pressure").asDouble()); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(mainNode.get("pressure").asDouble()); final JsonNode seaLevelNode = mainNode.get("sea_level"); final JsonNode groundLevelNode = mainNode.get("grnd_level"); @@ -205,7 +217,7 @@ public class CurrentWeatherResponseMapper { final JsonNode windNode = rootNode.get("wind"); double speed = windNode.get("speed").asDouble(); - Wind wind = Wind.withValue(speed, unitSystem.getWindUnit()); + final Wind wind = Wind.withValue(speed, unitSystem.getWindUnit()); final JsonNode degNode = windNode.get("deg"); if (degNode != null) { @@ -224,11 +236,11 @@ public class CurrentWeatherResponseMapper { if (rainNode != null) { final JsonNode oneHourNode = rainNode.get("1h"); final JsonNode threeHourNode = rainNode.get("3h"); - if (oneHourNode != null && oneHourNode.isDouble() && threeHourNode != null && threeHourNode.isDouble()) { + if (oneHourNode != null && threeHourNode != null) { return Rain.withValues(oneHourNode.asDouble(), threeHourNode.asDouble()); - } else if (oneHourNode != null && oneHourNode.isDouble()) { + } else if (oneHourNode != null) { return Rain.withOneHourLevelValue(oneHourNode.asDouble()); - } else if (threeHourNode != null && threeHourNode.isDouble()) { + } else if (threeHourNode != null) { return Rain.withThreeHourLevelValue(threeHourNode.asDouble()); } } @@ -240,11 +252,11 @@ public class CurrentWeatherResponseMapper { if (snowNode != null) { final JsonNode oneHourNode = snowNode.get("1h"); final JsonNode threeHourNode = snowNode.get("3h"); - if (oneHourNode != null && oneHourNode.isDouble() && threeHourNode != null && threeHourNode.isDouble()) { + if (oneHourNode != null && threeHourNode != null) { return Snow.withValues(oneHourNode.asDouble(), threeHourNode.asDouble()); - } else if (oneHourNode != null && oneHourNode.isDouble()) { + } else if (oneHourNode != null) { return Snow.withOneHourLevelValue(oneHourNode.asDouble()); - } else if (threeHourNode != null && threeHourNode.isDouble()) { + } else if (threeHourNode != null) { return Snow.withThreeHourLevelValue(threeHourNode.asDouble()); } } @@ -252,19 +264,17 @@ public class CurrentWeatherResponseMapper { } private Clouds parseClouds(JsonNode rootNode) { - Clouds clouds = null; - final JsonNode cloudsNode = rootNode.get("clouds"); final JsonNode allValueNode = cloudsNode.get("all"); if (allValueNode != null) { - clouds = Clouds.withValue((byte) allValueNode.asInt()); + return Clouds.withValue((byte) allValueNode.asInt()); } - return clouds; + return null; } private Location parseLocation(JsonNode rootNode) { - Location location = Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText()); + final Location location = Location.withValues(rootNode.get("id").asInt(), rootNode.get("name").asText()); final JsonNode timezoneNode = rootNode.get("timezone"); if (timezoneNode != null) { @@ -281,10 +291,10 @@ public class CurrentWeatherResponseMapper { final JsonNode sunriseNode = sysNode.get("sunrise"); final JsonNode sunsetNode = sysNode.get("sunset"); if (sunriseNode != null) { - location.setSunrise(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asInt()), TimeZone.getDefault().toZoneId())); + location.setSunriseTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunriseNode.asInt()), TimeZone.getDefault().toZoneId())); } if (sunsetNode != null) { - location.setSunset(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asInt()), TimeZone.getDefault().toZoneId())); + location.setSunsetTime(LocalDateTime.ofInstant(Instant.ofEpochSecond(sunsetNode.asInt()), TimeZone.getDefault().toZoneId())); } } @@ -297,10 +307,10 @@ public class CurrentWeatherResponseMapper { } private Coordinate parseCoordinate(JsonNode rootNode) { - JsonNode latitudeNode = rootNode.get("lat"); - JsonNode longitudeNode = rootNode.get("lon"); + final JsonNode latitudeNode = rootNode.get("lat"); + final JsonNode longitudeNode = rootNode.get("lon"); if (latitudeNode != null && longitudeNode != null) { - return Coordinate.withValues(latitudeNode.asDouble(), longitudeNode.asDouble()); + return Coordinate.of(latitudeNode.asDouble(), longitudeNode.asDouble()); } return null; } diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleLocationsCurrentWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleLocationsCurrentWeatherRequesterImpl.java index 6b28095..ba105cd 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleLocationsCurrentWeatherRequesterImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleLocationsCurrentWeatherRequesterImpl.java @@ -30,7 +30,6 @@ import com.github.prominence.openweathermap.api.model.CoordinateRectangle; * The type Multiple locations current weather requester. */ public class MultipleLocationsCurrentWeatherRequesterImpl implements MultipleLocationsCurrentWeatherRequester { - private final RequestUrlBuilder urlBuilder; /** diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl.java index 99b120b..189cfb3 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl.java @@ -35,7 +35,6 @@ import java.util.concurrent.CompletableFuture; * The type Multiple result current weather async request terminator. */ public class MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl implements MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer.java index b51357e..336b04c 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer.java @@ -28,7 +28,6 @@ import com.github.prominence.openweathermap.api.request.RequestCustomizer; * The interface Multiple result current weather request customizer. */ public interface MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer extends RequestCustomizer { - /** * Retrieve multiple result current weather request terminator. * diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl.java index 09935df..b753f5d 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl.java @@ -30,7 +30,6 @@ import com.github.prominence.openweathermap.api.request.RequestUrlBuilder; * The type Multiple result current weather request customizer. */ public class MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl implements MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer { - private final RequestUrlBuilder urlBuilder; private Language language; @@ -45,18 +44,6 @@ public class MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl imp this.urlBuilder = urlBuilder; } - @Override - public MultipleResultCitiesInCircleCurrentWeatherRequestTerminator retrieve() { - urlBuilder.applyCustomization(language, unitSystem); - return new MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); - } - - @Override - public MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminator retrieveAsync() { - urlBuilder.applyCustomization(language, unitSystem); - return new MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); - } - @Override public MultipleResultCitiesInCircleCurrentWeatherRequestCustomizer language(Language language) { this.language = language; @@ -68,4 +55,16 @@ public class MultipleResultCitiesInCircleCurrentWeatherRequestCustomizerImpl imp this.unitSystem = unitSystem; return this; } + + @Override + public MultipleResultCitiesInCircleCurrentWeatherRequestTerminator retrieve() { + urlBuilder.applyCustomization(language, unitSystem); + return new MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); + } + + @Override + public MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminator retrieveAsync() { + urlBuilder.applyCustomization(language, unitSystem); + return new MultipleResultCitiesInCircleCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); + } } \ No newline at end of file diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl.java index 6d22b90..7e482a2 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl.java @@ -34,7 +34,6 @@ import java.util.List; * The type Multiple result current weather request terminator. */ public class MultipleResultCitiesInCircleCurrentWeatherRequestTerminatorImpl implements MultipleResultCitiesInCircleCurrentWeatherRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherAsyncRequestTerminatorImpl.java index 876c73a..e34c195 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherAsyncRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherAsyncRequestTerminatorImpl.java @@ -35,7 +35,6 @@ import java.util.concurrent.CompletableFuture; * The type Multiple result current weather async request terminator. */ public class MultipleResultCurrentWeatherAsyncRequestTerminatorImpl implements MultipleResultCurrentWeatherAsyncRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizer.java index 57f5e06..651e413 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizer.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizer.java @@ -28,7 +28,6 @@ import com.github.prominence.openweathermap.api.request.RequestCustomizer; * The interface Multiple result current weather request customizer. */ public interface MultipleResultCurrentWeatherRequestCustomizer extends RequestCustomizer { - /** * Retrieve multiple result current weather request terminator. * diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizerImpl.java index 911ae54..78d14f8 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizerImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestCustomizerImpl.java @@ -30,7 +30,6 @@ import com.github.prominence.openweathermap.api.enums.UnitSystem; * The type Multiple result current weather request customizer. */ public class MultipleResultCurrentWeatherRequestCustomizerImpl implements MultipleResultCurrentWeatherRequestCustomizer { - private final RequestUrlBuilder urlBuilder; private Language language; @@ -45,18 +44,6 @@ public class MultipleResultCurrentWeatherRequestCustomizerImpl implements Multip this.urlBuilder = urlBuilder; } - @Override - public MultipleResultCurrentWeatherRequestTerminator retrieve() { - urlBuilder.applyCustomization(language, unitSystem); - return new MultipleResultCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); - } - - @Override - public MultipleResultCurrentWeatherAsyncRequestTerminator retrieveAsync() { - urlBuilder.applyCustomization(language, unitSystem); - return new MultipleResultCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); - } - @Override public MultipleResultCurrentWeatherRequestCustomizer language(Language language) { this.language = language; @@ -68,4 +55,16 @@ public class MultipleResultCurrentWeatherRequestCustomizerImpl implements Multip this.unitSystem = unitSystem; return this; } + + @Override + public MultipleResultCurrentWeatherRequestTerminator retrieve() { + urlBuilder.applyCustomization(language, unitSystem); + return new MultipleResultCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); + } + + @Override + public MultipleResultCurrentWeatherAsyncRequestTerminator retrieveAsync() { + urlBuilder.applyCustomization(language, unitSystem); + return new MultipleResultCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); + } } \ No newline at end of file diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestTerminatorImpl.java index dc1e927..3cf256a 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherRequestTerminatorImpl.java @@ -34,7 +34,6 @@ import java.util.List; * The type Multiple result current weather request terminator. */ public class MultipleResultCurrentWeatherRequestTerminatorImpl implements MultipleResultCurrentWeatherRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleLocationCurrentWeatherRequesterImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleLocationCurrentWeatherRequesterImpl.java index dd452e6..e26038b 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleLocationCurrentWeatherRequesterImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleLocationCurrentWeatherRequesterImpl.java @@ -29,7 +29,6 @@ import com.github.prominence.openweathermap.api.model.Coordinate; * The type Single location current weather requester. */ public class SingleLocationCurrentWeatherRequesterImpl implements SingleLocationCurrentWeatherRequester { - private final RequestUrlBuilder urlBuilder; /** diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherAsyncRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherAsyncRequestTerminatorImpl.java index 439671b..88f39b2 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherAsyncRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherAsyncRequestTerminatorImpl.java @@ -34,7 +34,6 @@ import java.util.concurrent.CompletableFuture; * The type Single result current weather async request terminator. */ public class SingleResultCurrentWeatherAsyncRequestTerminatorImpl implements SingleResultCurrentWeatherAsyncRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizer.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizer.java index 0ce8577..9661cf9 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizer.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizer.java @@ -28,7 +28,6 @@ import com.github.prominence.openweathermap.api.request.RequestCustomizer; * The current weather request customizer interface. */ public interface SingleResultCurrentWeatherRequestCustomizer extends RequestCustomizer { - /** * Retrieve current weather request terminator. * diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizerImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizerImpl.java index f8d149e..2734252 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizerImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestCustomizerImpl.java @@ -30,7 +30,6 @@ import com.github.prominence.openweathermap.api.enums.UnitSystem; * The type Single result current weather request customizer. */ public class SingleResultCurrentWeatherRequestCustomizerImpl implements SingleResultCurrentWeatherRequestCustomizer { - private final RequestUrlBuilder urlBuilder; private Language language; @@ -45,18 +44,6 @@ public class SingleResultCurrentWeatherRequestCustomizerImpl implements SingleRe this.urlBuilder = urlBuilder; } - @Override - public SingleResultCurrentWeatherRequestTerminator retrieve() { - urlBuilder.applyCustomization(language, unitSystem); - return new SingleResultCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); - } - - @Override - public SingleResultCurrentWeatherAsyncRequestTerminator retrieveAsync() { - urlBuilder.applyCustomization(language, unitSystem); - return new SingleResultCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); - } - @Override public SingleResultCurrentWeatherRequestCustomizer language(Language language) { this.language = language; @@ -68,4 +55,16 @@ public class SingleResultCurrentWeatherRequestCustomizerImpl implements SingleRe this.unitSystem = unitSystem; return this; } + + @Override + public SingleResultCurrentWeatherRequestTerminator retrieve() { + urlBuilder.applyCustomization(language, unitSystem); + return new SingleResultCurrentWeatherRequestTerminatorImpl(urlBuilder, unitSystem); + } + + @Override + public SingleResultCurrentWeatherAsyncRequestTerminator retrieveAsync() { + urlBuilder.applyCustomization(language, unitSystem); + return new SingleResultCurrentWeatherAsyncRequestTerminatorImpl(urlBuilder, unitSystem); + } } \ No newline at end of file diff --git a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestTerminatorImpl.java b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestTerminatorImpl.java index 76ec882..65be3ac 100644 --- a/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestTerminatorImpl.java +++ b/src/main/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherRequestTerminatorImpl.java @@ -32,7 +32,6 @@ import com.github.prominence.openweathermap.api.utils.RequestUtils; * The type Single result current weather request terminator. */ public class SingleResultCurrentWeatherRequestTerminatorImpl implements SingleResultCurrentWeatherRequestTerminator { - private final RequestUrlBuilder urlBuilder; private final UnitSystem unitSystem; diff --git a/src/test/java/com/github/prominence/openweathermap/api/ApiTest.java b/src/test/java/com/github/prominence/openweathermap/api/ApiTest.java index 9f564d7..ea42665 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/ApiTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/ApiTest.java @@ -22,19 +22,18 @@ package com.github.prominence.openweathermap.api; -import org.junit.BeforeClass; +import org.junit.jupiter.api.BeforeAll; public class ApiTest { + private static OpenWeatherMapClient client; - private static OpenWeatherMapClient manager; - - @BeforeClass + @BeforeAll public static void retrieveApiKey() { String apiKey = System.getenv("OPENWEATHER_API_KEY"); - manager = new OpenWeatherMapClient(apiKey); + client = new OpenWeatherMapClient(apiKey); } protected static OpenWeatherMapClient getClient() { - return manager; + return client; } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/enums/WeatherConditionUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/enums/WeatherConditionUnitTest.java new file mode 100644 index 0000000..908483d --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/enums/WeatherConditionUnitTest.java @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.enums; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class WeatherConditionUnitTest { + @Test + public void getId() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotEquals(0, weatherCondition.getId()); + } + + @Test + public void getName() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getName()); + assertNotEquals("", weatherCondition.getName()); + } + + @Test + public void getDescription() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getDescription()); + assertNotEquals("", weatherCondition.getDescription()); + } + + @Test + public void getDayIconId() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getDayIconId()); + assertNotEquals("", weatherCondition.getDayIconId()); + } + + @Test + public void getNightIconId() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getNightIconId()); + assertNotEquals("", weatherCondition.getNightIconId()); + } + + @Test + public void getDayIconUrl() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getDayIconUrl()); + assertNotEquals("", weatherCondition.getDayIconUrl()); + } + + @Test + public void getNightIconUrl() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.getNightIconUrl()); + assertNotEquals("", weatherCondition.getNightIconUrl()); + } + + @Test + public void getIconUrl() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(WeatherCondition.getIconUrl(weatherCondition.getNightIconId())); + assertNotEquals("", WeatherCondition.getIconUrl(weatherCondition.getNightIconId())); + } + + @Test + public void getById() { + assertEquals(WeatherCondition.ASH, WeatherCondition.getById(WeatherCondition.ASH.getId())); + } + + @Test + public void testToString() { + final WeatherCondition weatherCondition = WeatherCondition.ASH; + + assertNotNull(weatherCondition.toString()); + assertNotEquals("", weatherCondition.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/AtmosphericPressureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/AtmosphericPressureUnitTest.java index c8d98e4..f053ad7 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/AtmosphericPressureUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/AtmosphericPressureUnitTest.java @@ -20,42 +20,21 @@ * SOFTWARE. */ -/* - * Copyright (c) 2021 Alexey Zinchenko - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class AtmosphericPressureUnitTest { @Test public void whenCreatePressureWithArgs_thenValueIsSet() { AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(100); - Assert.assertEquals(100, atmosphericPressure.getValue(), 0.00001); + assertEquals(100, atmosphericPressure.getValue(), 0.00001); - Assert.assertEquals(0, AtmosphericPressure.withValue(0).getValue(), 0.00001); - Assert.assertEquals(100, AtmosphericPressure.withValue(100).getValue(), 0.00001); - Assert.assertEquals(55, AtmosphericPressure.withValue(55).getValue(), 0.00001); + assertEquals(0, AtmosphericPressure.withValue(0).getValue(), 0.00001); + assertEquals(100, AtmosphericPressure.withValue(100).getValue(), 0.00001); + assertEquals(55, AtmosphericPressure.withValue(55).getValue(), 0.00001); } @Test @@ -63,9 +42,9 @@ public class AtmosphericPressureUnitTest { AtmosphericPressure one = AtmosphericPressure.withValue(22); AtmosphericPressure two = AtmosphericPressure.withValue(22); - Assert.assertTrue(one.equals(two)); - Assert.assertTrue(one.equals(one)); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one, two); + assertEquals(one, one); + assertEquals(one.hashCode(), two.hashCode()); one.setSeaLevelValue(333); one.setGroundLevelValue(555); @@ -73,9 +52,9 @@ public class AtmosphericPressureUnitTest { two.setSeaLevelValue(333); two.setGroundLevelValue(555); - Assert.assertTrue(one.equals(two)); - Assert.assertTrue(two.equals(one)); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one, two); + assertEquals(two, one); + assertEquals(one.hashCode(), two.hashCode()); } @Test @@ -83,23 +62,23 @@ public class AtmosphericPressureUnitTest { AtmosphericPressure one = AtmosphericPressure.withValue(5); AtmosphericPressure two = AtmosphericPressure.withValue(88); - Assert.assertFalse(one.equals(two)); - Assert.assertFalse(two.equals(one)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one, two); + assertNotEquals(two, one); + assertNotEquals(one, new Object()); + assertNotEquals(one.hashCode(), two.hashCode()); one = AtmosphericPressure.withValue(44); one.setSeaLevelValue(44); two = AtmosphericPressure.withValue(44); two.setGroundLevelValue(22); - Assert.assertFalse(one.equals(two)); - Assert.assertFalse(two.equals(one)); + assertNotEquals(one, two); + assertNotEquals(two, one); two.setSeaLevelValue(44); - Assert.assertFalse(one.equals(two)); - Assert.assertFalse(two.equals(one)); + assertNotEquals(one, two); + assertNotEquals(two, one); } @Test @@ -110,39 +89,42 @@ public class AtmosphericPressureUnitTest { atmosphericPressure.setValue(100); atmosphericPressure.setGroundLevelValue(222); - Assert.assertEquals(222, atmosphericPressure.getGroundLevelValue(), 0.00001); + assertEquals(222, atmosphericPressure.getGroundLevelValue(), 0.00001); atmosphericPressure.setSeaLevelValue(4232); - Assert.assertEquals(4232, atmosphericPressure.getSeaLevelValue(), 0.00001); + assertEquals(4232, atmosphericPressure.getSeaLevelValue(), 0.00001); } @Test public void whenCallToString_thenAllIsFine() { final String pressureString = AtmosphericPressure.withValue(44).toString(); - Assert.assertNotNull(pressureString); - Assert.assertNotEquals("", pressureString); + assertNotNull(pressureString); + assertNotEquals("", pressureString); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreatePressureByConstructorWithInvalidDataNegative_thenThrowAnException() { - AtmosphericPressure.withValue(-33); + assertThrows(IllegalArgumentException.class, () -> AtmosphericPressure.withValue(-33)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreatePressureAndSetInvalidDataNegative_thenThrowAnException() { AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(88); - atmosphericPressure.setValue(-89); + + assertThrows(IllegalArgumentException.class, () -> atmosphericPressure.setValue(-89)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidSeaLevelPressure_thenThrowAnException() { AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(88); - atmosphericPressure.setSeaLevelValue(-89); + + assertThrows(IllegalArgumentException.class, () -> atmosphericPressure.setSeaLevelValue(-89)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidGroundLevelPressure_thenThrowAnException() { AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(88); - atmosphericPressure.setGroundLevelValue(-223); + + assertThrows(IllegalArgumentException.class, () -> atmosphericPressure.setGroundLevelValue(-223)); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/CloudsUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/CloudsUnitTest.java index caa25dd..f01590c 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/CloudsUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/CloudsUnitTest.java @@ -20,75 +20,56 @@ * SOFTWARE. */ -/* - * Copyright (c) 2021 Alexey Zinchenko - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class CloudsUnitTest { @Test public void whenCreateCloudsWithValidArgs_thenValueIsSet() { Clouds clouds = Clouds.withValue((byte) 100); - Assert.assertEquals(100, clouds.getValue()); + assertEquals(100, clouds.getValue()); - Assert.assertEquals(0, Clouds.withValue((byte) 0).getValue()); - Assert.assertEquals(100, Clouds.withValue((byte) 100).getValue()); - Assert.assertEquals(55, Clouds.withValue((byte) 55).getValue()); + assertEquals(0, Clouds.withValue((byte) 0).getValue()); + assertEquals(100, Clouds.withValue((byte) 100).getValue()); + assertEquals(55, Clouds.withValue((byte) 55).getValue()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCloudsByConstructorWithInvalidDataAboveHundred_thenThrowAnException() { - Clouds.withValue((byte) 110); + assertThrows(IllegalArgumentException.class, () -> Clouds.withValue((byte) 110)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCloudsByConstructorWithInvalidDataNegative_thenThrowAnException() { - Clouds.withValue((byte) -33); + assertThrows(IllegalArgumentException.class, () -> Clouds.withValue((byte) -33)); } @Test public void whenSetValidValues_thenAllIsFine() { Clouds clouds = Clouds.withValue((byte) 14); clouds.setValue((byte) 0); - Assert.assertEquals(0, clouds.getValue()); + assertEquals(0, clouds.getValue()); clouds.setValue((byte) 15); - Assert.assertEquals(15, clouds.getValue()); + assertEquals(15, clouds.getValue()); clouds.setValue((byte) 100); - Assert.assertEquals(100, clouds.getValue()); + assertEquals(100, clouds.getValue()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCloudsAndSetInvalidDataAboveHundred_thenThrowAnException() { Clouds clouds = Clouds.withValue((byte) 12); - clouds.setValue((byte) 112); + + assertThrows(IllegalArgumentException.class, () -> clouds.setValue((byte) 112)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCloudsAndSetInvalidDataNegative_thenThrowAnException() { Clouds clouds = Clouds.withValue((byte) 88); - clouds.setValue((byte) -89); + + assertThrows(IllegalArgumentException.class, () -> clouds.setValue((byte) -89)); } @Test @@ -96,9 +77,9 @@ public class CloudsUnitTest { Clouds one = Clouds.withValue((byte) 22); Clouds two = Clouds.withValue((byte) 22); - Assert.assertTrue(one.equals(two)); - Assert.assertTrue(one.equals(one)); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one, two); + assertEquals(one, one); + assertEquals(one.hashCode(), two.hashCode()); } @Test @@ -106,16 +87,16 @@ public class CloudsUnitTest { Clouds one = Clouds.withValue((byte) 5); Clouds two = Clouds.withValue((byte) 88); - Assert.assertFalse(one.equals(two)); - Assert.assertFalse(two.equals(one)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one, two); + assertNotEquals(two, one); + assertNotEquals(one, new Object()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test public void whenCallToString_thenAllIsFine() { final String cloudsString = Clouds.withValue((byte) 44).toString(); - Assert.assertNotNull(cloudsString); - Assert.assertNotEquals("", cloudsString); + assertNotNull(cloudsString); + assertNotEquals("", cloudsString); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateRectangleUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateRectangleUnitTest.java index 68339c9..8e05dc8 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateRectangleUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateRectangleUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class CoordinateRectangleUnitTest { @Test @@ -31,102 +32,160 @@ public class CoordinateRectangleUnitTest { CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLatitudeBottomBelowMinus90_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, -91.2, 54.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, -91.2, 54.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLatitudeBottomAbove90_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, 91.2, 54.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, 91.2, 54.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLatitudeTopBelowMinus90_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, 22.4, 54.4, -92.3); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, 22.4, 54.4, -92.3)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLatitudeTopAbove90_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, 22.5, 54.4, 94.887); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, 22.5, 54.4, 94.887)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLongitudeLeftBelowMinus180_thenThrowAnException() { - CoordinateRectangle.withValues(-944.5, 22.4, 54.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(-944.5, 22.4, 54.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLongitudeLeftAbove180_thenThrowAnException() { - CoordinateRectangle.withValues(544.5, 22.4, 54.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(544.5, 22.4, 54.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLongitudeRightBelowMinus180_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, 22.4, -254.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, 22.4, -254.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithLongitudeRightAbove180_thenThrowAnException() { - CoordinateRectangle.withValues(44.5, 22.4, 354.4, 22.2); + assertThrows(IllegalArgumentException.class, () -> CoordinateRectangle.withValues(44.5, 22.4, 354.4, 22.2)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectUsingBuilderWithInvalidLatitudeBottom_thenFail() { - new CoordinateRectangle.Builder() - .setLatitudeBottom(-1000); + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLatitudeBottom(-1000)); } - @Test(expected = IllegalArgumentException.class) + @Test + public void whenCreateObjectUsingBuilderWithInvalidLatitudeBottom2_thenFail() { + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLatitudeBottom(1000)); + } + + @Test public void whenCreateObjectUsingBuilderWithInvalidLatitudeTop_thenFail() { - new CoordinateRectangle.Builder() - .setLatitudeTop(-1000); + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLatitudeTop(-1000)); } - @Test(expected = IllegalArgumentException.class) + @Test + public void whenCreateObjectUsingBuilderWithInvalidLatitudeTop2_thenFail() { + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLatitudeTop(1000)); + } + + @Test public void whenCreateObjectUsingBuilderWithInvalidLongitudeLeft_thenFail() { - new CoordinateRectangle.Builder() - .setLongitudeLeft(-1000); + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeLeft(-1000)); } - @Test(expected = IllegalArgumentException.class) + @Test + public void whenCreateObjectUsingBuilderWithInvalidLongitudeLeft2_thenFail() { + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeLeft(1000)); + } + + @Test public void whenCreateObjectUsingBuilderWithInvalidLongitudeRight_thenFail() { - new CoordinateRectangle.Builder() - .setLongitudeRight(-1000); + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeRight(-1000)); } - @Test(expected = IllegalStateException.class) + @Test + public void whenCreateObjectUsingBuilderWithInvalidLongitudeRight2_thenFail() { + assertThrows(IllegalArgumentException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeRight(1000)); + } + + @Test public void whenCreateObjectUsingBuilderWithoutAllPropertiesSet_thenFail() { - new CoordinateRectangle.Builder() + assertThrows(IllegalStateException.class, () -> new CoordinateRectangle.Builder() + .build()); + } + + @Test + public void whenCreateObjectUsingBuilderWithoutAllPropertiesSet1_thenFail() { + assertThrows(IllegalStateException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeLeft(10) + .build()); + } + + @Test + public void whenCreateObjectUsingBuilderWithoutAllPropertiesSet2_thenFail() { + assertThrows(IllegalStateException.class, () -> new CoordinateRectangle.Builder() .setLongitudeRight(10) - .build(); + .setLatitudeBottom(10) + .build()); + } + + @Test + public void whenCreateObjectUsingBuilderWithoutAllPropertiesSet3_thenFail() { + assertThrows(IllegalStateException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeLeft(10) + .setLatitudeBottom(10) + .setLongitudeRight(10) + .build()); + } + + @Test + public void whenCreateObjectUsingBuilderWithoutAllPropertiesSet4_thenFail() { + assertThrows(IllegalStateException.class, () -> new CoordinateRectangle.Builder() + .setLongitudeLeft(10) + .setLatitudeTop(10) + .setLatitudeBottom(10) + .build()); } @Test public void whenCreateObjectUsingBuilderWithCorrectUsage_thenOk() { - new CoordinateRectangle.Builder() + final CoordinateRectangle rectangle = new CoordinateRectangle.Builder() .setLongitudeRight(10) .setLongitudeLeft(10) .setLatitudeTop(10) .setLatitudeBottom(10) .build(); + + assertNotNull(rectangle); } @Test public void whenGetAllParameters_thenAllIsFine() { final CoordinateRectangle rectangle = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); - Assert.assertEquals(44.5, rectangle.getLongitudeLeft(), 0.00001); - Assert.assertEquals(22.4, rectangle.getLatitudeBottom(), 0.00001); - Assert.assertEquals(54.4, rectangle.getLongitudeRight(), 0.00001); - Assert.assertEquals(22.2, rectangle.getLatitudeTop(), 0.00001); + assertEquals(44.5, rectangle.getLongitudeLeft(), 0.00001); + assertEquals(22.4, rectangle.getLatitudeBottom(), 0.00001); + assertEquals(54.4, rectangle.getLongitudeRight(), 0.00001); + assertEquals(22.2, rectangle.getLatitudeTop(), 0.00001); } @Test public void whenCallToString_thenAllIsFine() { final CoordinateRectangle rectangle = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); - Assert.assertNotNull(rectangle.toString()); - Assert.assertNotEquals("", rectangle.toString()); + assertNotNull(rectangle.toString()); + assertNotEquals("", rectangle.toString()); } @Test @@ -134,12 +193,12 @@ public class CoordinateRectangleUnitTest { final CoordinateRectangle first = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); final CoordinateRectangle second = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); final CoordinateRectangle third = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 23.566); - Assert.assertNotEquals(first.hashCode(), third.hashCode()); - Assert.assertNotEquals(second.hashCode(), third.hashCode()); + assertNotEquals(first.hashCode(), third.hashCode()); + assertNotEquals(second.hashCode(), third.hashCode()); } @Test @@ -147,24 +206,24 @@ public class CoordinateRectangleUnitTest { CoordinateRectangle first = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); CoordinateRectangle second = CoordinateRectangle.withValues(44.5, 22.4, 54.4, 22.2); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); first = CoordinateRectangle.withValues(49.5, 22.4, 54.4, 22.2); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first = CoordinateRectangle.withValues(44.5, 29.4, 54.4, 22.2); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first = CoordinateRectangle.withValues(44.5, 22.4, 24.4, 22.2); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first = CoordinateRectangle.withValues(44.5, 22.4, 54.4, -2.2); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateUnitTest.java index 8482ce1..8b358b3 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/CoordinateUnitTest.java @@ -22,148 +22,150 @@ package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class CoordinateUnitTest { + @Test public void whenCreateCoordinateWithValidValues_thenObjectCreated() { - Coordinate.withValues(44, 53); + Coordinate.of(44, 53); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCoordinateWithInvalidLatitudeBelowMinus90_thenThrowAnException() { - Coordinate.withValues(-333, 44); + assertThrows(IllegalArgumentException.class, () -> Coordinate.of(-333, 44)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCoordinateWithInvalidLatitudeAbove90_thenThrowAnException() { - Coordinate.withValues(223, 44); + assertThrows(IllegalArgumentException.class, () -> Coordinate.of(223, 44)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCoordinateWithInvalidLongitudeBelowMinus180_thenThrowAnException() { - Coordinate.withValues(33, -999); + assertThrows(IllegalArgumentException.class, () -> Coordinate.of(33, -999)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateCoordinateWithInvalidLongitudeAbove180_thenThrowAnException() { - Coordinate.withValues(33, 999); + assertThrows(IllegalArgumentException.class, () -> Coordinate.of(33, 999)); } @Test public void whenSetValidCoordinates_thenAllIsFine() { - final Coordinate coordinate = Coordinate.withValues(0, 0); + final Coordinate coordinate = Coordinate.of(0, 0); coordinate.setLatitude(-90); - Assert.assertEquals(-90, coordinate.getLatitude(), 0.00001); + assertEquals(-90, coordinate.getLatitude(), 0.00001); coordinate.setLatitude(90); - Assert.assertEquals(90, coordinate.getLatitude(), 0.00001); + assertEquals(90, coordinate.getLatitude(), 0.00001); coordinate.setLatitude(44); - Assert.assertEquals(44, coordinate.getLatitude(), 0.00001); + assertEquals(44, coordinate.getLatitude(), 0.00001); coordinate.setLongitude(-180); - Assert.assertEquals(-180, coordinate.getLongitude(), 0.00001); + assertEquals(-180, coordinate.getLongitude(), 0.00001); coordinate.setLongitude(180); - Assert.assertEquals(180, coordinate.getLongitude(), 0.00001); + assertEquals(180, coordinate.getLongitude(), 0.00001); coordinate.setLongitude(130); - Assert.assertEquals(130, coordinate.getLongitude(), 0.00001); + assertEquals(130, coordinate.getLongitude(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidLatitudeBelowMinus90_thenThrowAnException() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - coordinate.setLatitude(-91); + final Coordinate coordinate = Coordinate.of(0, 0); + assertThrows(IllegalArgumentException.class, () -> coordinate.setLatitude(-91)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidLatitudeAbove90_thenThrowAnException() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - coordinate.setLatitude(92); + final Coordinate coordinate = Coordinate.of(0, 0); + assertThrows(IllegalArgumentException.class, () -> coordinate.setLatitude(92)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidLongitudeBelowMinus180_thenThrowAnException() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - coordinate.setLongitude(-194); + final Coordinate coordinate = Coordinate.of(0, 0); + assertThrows(IllegalArgumentException.class, () -> coordinate.setLongitude(-194)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidLongitudeAbove180_thenThrowAnException() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - coordinate.setLongitude(444); + final Coordinate coordinate = Coordinate.of(0, 0); + assertThrows(IllegalArgumentException.class, () -> coordinate.setLongitude(444)); } @Test public void whenGetLatitude_thenAllIsFine() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - Assert.assertEquals(0, coordinate.getLatitude(), 0.00001); + final Coordinate coordinate = Coordinate.of(0, 0); + assertEquals(0, coordinate.getLatitude(), 0.00001); coordinate.setLatitude(45); - Assert.assertEquals(45, coordinate.getLatitude(), 0.00001); + assertEquals(45, coordinate.getLatitude(), 0.00001); } @Test public void whenGetLongitude_thenAllIsFine() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - Assert.assertEquals(0, coordinate.getLongitude(), 0.00001); + final Coordinate coordinate = Coordinate.of(0, 0); + assertEquals(0, coordinate.getLongitude(), 0.00001); coordinate.setLongitude(33); - Assert.assertEquals(33, coordinate.getLongitude(), 0.00001); + assertEquals(33, coordinate.getLongitude(), 0.00001); } @Test public void whenCallToString_thenAllIsFine() { - final Coordinate coordinate = Coordinate.withValues(0, 0); - Assert.assertNotNull(coordinate.toString()); - Assert.assertNotEquals("", coordinate.toString()); + final Coordinate coordinate = Coordinate.of(0, 0); + assertNotNull(coordinate.toString()); + assertNotEquals("", coordinate.toString()); } @Test public void whenCallHashCode_thenAllIsFine() { - final Coordinate first = Coordinate.withValues(22, 66); - final Coordinate second = Coordinate.withValues(22, 44); + final Coordinate first = Coordinate.of(22, 66); + final Coordinate second = Coordinate.of(22, 44); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); second.setLongitude(66); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); second.setLatitude(89); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); first.setLatitude(89); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test public void whenCheckEquality_thenAllIsFine() { - final Coordinate first = Coordinate.withValues(11, 99); - final Coordinate second = Coordinate.withValues(11, 99); + final Coordinate first = Coordinate.of(11, 99); + final Coordinate second = Coordinate.of(11, 99); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); first.setLatitude(34); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); second.setLatitude(34); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); second.setLongitude(74); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first.setLongitude(74); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/DayTimeUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/DayTimeUnitTest.java index b920299..5167503 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/DayTimeUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/DayTimeUnitTest.java @@ -22,13 +22,14 @@ package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class DayTimeUnitTest { @Test public void whenGetValue_thenValueIsPresentAndValid() { - Assert.assertEquals("d", DayTime.DAY.getValue()); - Assert.assertEquals("n", DayTime.NIGHT.getValue()); + assertEquals("d", DayTime.DAY.getValue()); + assertEquals("n", DayTime.NIGHT.getValue()); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/HumidityUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/HumidityUnitTest.java index 7d3d490..ab0d11d 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/HumidityUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/HumidityUnitTest.java @@ -22,51 +22,52 @@ package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class HumidityUnitTest { @Test public void whenCreateHumidityWithArgs_thenValueIsSet() { Humidity humidity = Humidity.withValue((byte) 100); - Assert.assertEquals(100, humidity.getValue()); + assertEquals(100, humidity.getValue()); - Assert.assertEquals(0, Humidity.withValue((byte) 0).getValue()); - Assert.assertEquals(55, Humidity.withValue((byte) 55).getValue()); + assertEquals(0, Humidity.withValue((byte) 0).getValue()); + assertEquals(55, Humidity.withValue((byte) 55).getValue()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateHumidityByConstructorWithInvalidDataAboveHundred_thenThrowAnException() { - Humidity.withValue((byte) 112); + assertThrows(IllegalArgumentException.class, () -> Humidity.withValue((byte) 112)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateHumidityByConstructorWithInvalidDataNegative_thenThrowAnException() { - Humidity.withValue((byte) -33); + assertThrows(IllegalArgumentException.class, () -> Humidity.withValue((byte) -33)); } @Test public void whenSetValidValues_thenAllIsFine() { Humidity humidity = Humidity.withValue((byte) 14); - Assert.assertEquals(14, humidity.getValue()); + assertEquals(14, humidity.getValue()); humidity.setValue((byte) 0); - Assert.assertEquals(0, humidity.getValue()); + assertEquals(0, humidity.getValue()); humidity.setValue((byte) 15); - Assert.assertEquals(15, humidity.getValue()); + assertEquals(15, humidity.getValue()); humidity.setValue((byte) 100); - Assert.assertEquals(100, humidity.getValue()); + assertEquals(100, humidity.getValue()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateHumidityAndSetInvalidDataAboveHundred_thenThrowAnException() { Humidity humidity = Humidity.withValue((byte) 12); - humidity.setValue((byte) 112); + assertThrows(IllegalArgumentException.class, () -> humidity.setValue((byte) 112)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateHumidityAndSetInvalidDataNegative_thenThrowAnException() { Humidity humidity = Humidity.withValue((byte) 88); - humidity.setValue((byte) -89); + assertThrows(IllegalArgumentException.class, () -> humidity.setValue((byte) -89)); } @Test @@ -74,9 +75,9 @@ public class HumidityUnitTest { Humidity one = Humidity.withValue((byte) 22); Humidity two = Humidity.withValue((byte) 22); - Assert.assertTrue(one.equals(two)); - Assert.assertTrue(one.equals(one)); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one, two); + assertEquals(one, one); + assertEquals(one.hashCode(), two.hashCode()); } @Test @@ -84,16 +85,16 @@ public class HumidityUnitTest { Humidity one = Humidity.withValue((byte) 5); Humidity two = Humidity.withValue((byte) 88); - Assert.assertFalse(one.equals(two)); - Assert.assertFalse(two.equals(one)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one, two); + assertNotEquals(two, one); + assertNotEquals(one, new Object()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test public void whenCallToString_thenAllIsFine() { final String humidityString = Humidity.withValue((byte) 44).toString(); - Assert.assertNotNull(humidityString); - Assert.assertNotEquals("", humidityString); + assertNotNull(humidityString); + assertNotEquals("", humidityString); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/TemperatureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/TemperatureUnitTest.java index aee2034..716102d 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/TemperatureUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/TemperatureUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class TemperatureUnitTest { @Test @@ -31,9 +32,9 @@ public class TemperatureUnitTest { Temperature.withValue(22.2, "K"); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithEmptyUnit_thenThrowAnException() { - Temperature.withValue(22.2, null); + assertThrows(IllegalArgumentException.class, () -> Temperature.withValue(22.2, null)); } @Test @@ -41,7 +42,7 @@ public class TemperatureUnitTest { final Temperature temperature = Temperature.withValue(22.2, "K"); temperature.setValue(55.44); - Assert.assertEquals(55.44, temperature.getValue(), 0.00001); + assertEquals(55.44, temperature.getValue(), 0.00001); } @Test @@ -49,11 +50,11 @@ public class TemperatureUnitTest { final Temperature temperature = Temperature.withValue(22.2, "K"); temperature.setMaxTemperature(44.4); - Assert.assertEquals(44.4, temperature.getMaxTemperature(), 0.00001); + assertEquals(44.4, temperature.getMaxTemperature(), 0.00001); temperature.setMaxTemperature(null); - Assert.assertNull(temperature.getMaxTemperature()); + assertNull(temperature.getMaxTemperature()); } @Test @@ -61,11 +62,11 @@ public class TemperatureUnitTest { final Temperature temperature = Temperature.withValue(22.2, "K"); temperature.setMinTemperature(33.2); - Assert.assertEquals(33.2, temperature.getMinTemperature(), 0.00001); + assertEquals(33.2, temperature.getMinTemperature(), 0.00001); temperature.setMinTemperature(null); - Assert.assertNull(temperature.getMinTemperature()); + assertNull(temperature.getMinTemperature()); } @Test @@ -73,11 +74,11 @@ public class TemperatureUnitTest { final Temperature temperature = Temperature.withValue(22.2, "K"); temperature.setFeelsLike(22.3); - Assert.assertEquals(22.3, temperature.getFeelsLike(), 0.00001); + assertEquals(22.3, temperature.getFeelsLike(), 0.00001); temperature.setFeelsLike(null); - Assert.assertNull(temperature.getFeelsLike()); + assertNull(temperature.getFeelsLike()); } @Test @@ -85,37 +86,37 @@ public class TemperatureUnitTest { final Temperature temperature = Temperature.withValue(22.2, "K"); temperature.setUnit("test"); - Assert.assertTrue("test".equals(temperature.getUnit())); + assertEquals("test", temperature.getUnit()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetNullUnit_thenThrowAnException() { final Temperature temperature = Temperature.withValue(22.2, "K"); - temperature.setUnit(null); + assertThrows(IllegalArgumentException.class, () -> temperature.setUnit(null)); } @Test public void whenCallToString_thenAllIsFine() { final Temperature temperature = Temperature.withValue(22.2, "K"); - Assert.assertNotNull(temperature.toString()); - Assert.assertNotEquals("", temperature.toString()); + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); temperature.setMinTemperature(11.2); - Assert.assertNotNull(temperature.toString()); - Assert.assertNotEquals("", temperature.toString()); + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); temperature.setMaxTemperature(44.3); - Assert.assertNotNull(temperature.toString()); - Assert.assertNotEquals("", temperature.toString()); + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); temperature.setFeelsLike(22.4); - Assert.assertNotNull(temperature.toString()); - Assert.assertNotEquals("", temperature.toString()); + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); } @Test @@ -123,7 +124,7 @@ public class TemperatureUnitTest { final Temperature one = Temperature.withValue(22.2, "K"); final Temperature two = Temperature.withValue(22.2, "K"); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one.hashCode(), two.hashCode()); } @Test @@ -131,44 +132,44 @@ public class TemperatureUnitTest { final Temperature one = Temperature.withValue(22.2, "K"); final Temperature two = Temperature.withValue(21.2, "K"); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertFalse(one.equals(two)); + assertEquals(one, one); + assertNotEquals(one, new Object()); + assertNotEquals(one, two); one.setValue(21.2); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setMaxTemperature(33.56); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setMaxTemperature(33.56); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setMinTemperature(11.54); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setMinTemperature(11.54); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); two.setUnit("U"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); one.setUnit("U"); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setFeelsLike(22.3); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setFeelsLike(22.3); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/WeatherStateUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/WeatherStateUnitTest.java new file mode 100644 index 0000000..c0da7ef --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/WeatherStateUnitTest.java @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model; + +import com.github.prominence.openweathermap.api.enums.WeatherCondition; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class WeatherStateUnitTest { + @Test + public void getId() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + assertEquals(800, weatherState.getId()); + } + + @Test + public void getName() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + assertEquals("Clear", weatherState.getName()); + } + + @Test + public void getDescription() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + assertEquals("clear sky", weatherState.getDescription()); + } + + @Test + public void getIconId() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + weatherState.setIconId("04d"); + + assertEquals("04d", weatherState.getIconId()); + } + + @Test + public void getWeatherConditionEnum() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + assertEquals(WeatherCondition.CLEAR, weatherState.getWeatherConditionEnum()); + } + + @Test + public void getWeatherIconUrl() { + WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + String weatherIconUrl = weatherState.getWeatherIconUrl(); + + assertNotNull(weatherIconUrl); + assertNotEquals("", weatherIconUrl); + + weatherState.setIconId("04n"); + weatherIconUrl = weatherState.getWeatherIconUrl(); + + assertNotNull(weatherIconUrl); + assertNotEquals("", weatherIconUrl); + + weatherState = new WeatherState(0, "Unknown", "unknown"); + weatherIconUrl = weatherState.getWeatherIconUrl(); + + assertNull(weatherIconUrl); + } + + @Test + public void testEquals() { + final WeatherState first = new WeatherState(800, "Clear", "clear sky"); + final WeatherState second = new WeatherState(800, "Clear", "clear sky"); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + assertNotEquals(new WeatherState(800, "Clear", "clear sky"), new WeatherState(801, "Clear", "clear sky")); + assertNotEquals(new WeatherState(800, "Clear", "clear sky"), new WeatherState(800, "Clear1", "clear sky")); + assertNotEquals(new WeatherState(800, "Clear", "clear sky"), new WeatherState(800, "Clear", "clear sky1")); + + first.setIconId("50d"); + + assertNotEquals(first, second); + } + + @Test + public void testHashCode() { + final WeatherState first = new WeatherState(800, "Clear", "clear sky"); + final WeatherState second = new WeatherState(800, "Clear", "clear sky"); + final WeatherState third = new WeatherState(0, "Unknown", "unknown"); + + assertEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), third.hashCode()); + assertNotEquals(second.hashCode(), third.hashCode()); + } + + @Test + public void testToString() { + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + assertNotNull(weatherState.toString()); + assertNotEquals("", weatherState.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/ForecastUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/ForecastUnitTest.java index dd360b1..164d935 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/ForecastUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/ForecastUnitTest.java @@ -22,18 +22,19 @@ package com.github.prominence.openweathermap.api.model.forecast; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.ArrayList; +import static org.junit.jupiter.api.Assertions.*; + public class ForecastUnitTest { @Test public void whenLocationIsSet_thenAllIsOk() { final Forecast forecast = new Forecast(); forecast.setLocation(Location.withValues(2, "asd")); - Assert.assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getLocation()); } @Test @@ -41,7 +42,7 @@ public class ForecastUnitTest { final Forecast forecast = new Forecast(); forecast.setWeatherForecasts(new ArrayList<>()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast.getWeatherForecasts()); } @Test @@ -49,11 +50,11 @@ public class ForecastUnitTest { final Forecast one = new Forecast(); final Forecast two = new Forecast(); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one.hashCode(), two.hashCode()); one.setLocation(Location.withValues(22, "444")); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test @@ -61,21 +62,21 @@ public class ForecastUnitTest { final Forecast one = new Forecast(); final Forecast two = new Forecast(); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(null)); - Assert.assertTrue(one.equals(two)); - Assert.assertFalse(one.equals(new Object())); + assertEquals(one, one); + assertNotEquals(one, null); + assertEquals(one, two); + assertNotEquals(one, new Object()); one.setLocation(Location.withValues(22, "234")); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setLocation(one.getLocation()); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setWeatherForecasts(new ArrayList<>()); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/LocationUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/LocationUnitTest.java index 3aba580..303c464 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/LocationUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/LocationUnitTest.java @@ -23,21 +23,22 @@ package com.github.prominence.openweathermap.api.model.forecast; import com.github.prominence.openweathermap.api.model.Coordinate; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZoneOffset; +import static org.junit.jupiter.api.Assertions.*; + public class LocationUnitTest { @Test public void whenCreateObjectWithValidArgs_thenObjectIsCreated() { Location.withValues(33, "test"); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithoutName_thenThrowAnException() { - Location.withValues(33, null); + assertThrows(IllegalArgumentException.class, () -> Location.withValues(33, null)); } @Test @@ -45,7 +46,7 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setId(55); - Assert.assertEquals(55, location.getId()); + assertEquals(55, location.getId()); } @Test @@ -53,7 +54,7 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setName("city"); - Assert.assertEquals("city", location.getName()); + assertEquals("city", location.getName()); } @Test @@ -61,25 +62,25 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setCountryCode("by"); - Assert.assertEquals("by", location.getCountryCode()); + assertEquals("by", location.getCountryCode()); } @Test public void whenSetSunrise_thenValueIsSet() { final Location location = Location.withValues(33, "test"); final LocalDateTime now = LocalDateTime.now(); - location.setSunrise(now); + location.setSunriseTime(now); - Assert.assertEquals(now, location.getSunrise()); + assertEquals(now, location.getSunriseTime()); } @Test public void whenSetSunset_thenValueIsSet() { final Location location = Location.withValues(33, "test"); final LocalDateTime now = LocalDateTime.now(); - location.setSunset(now); + location.setSunsetTime(now); - Assert.assertEquals(now, location.getSunset()); + assertEquals(now, location.getSunsetTime()); } @Test @@ -88,16 +89,16 @@ public class LocationUnitTest { final ZoneOffset offset = ZoneOffset.UTC; location.setZoneOffset(offset); - Assert.assertEquals(offset, location.getZoneOffset()); + assertEquals(offset, location.getZoneOffset()); } @Test public void whenSetCoordinate_thenValueIsSet() { final Location location = Location.withValues(33, "test"); - final Coordinate coordinate = Coordinate.withValues(33.2, 64.2); + final Coordinate coordinate = Coordinate.of(33.2, 64.2); location.setCoordinate(coordinate); - Assert.assertEquals(coordinate, location.getCoordinate()); + assertEquals(coordinate, location.getCoordinate()); } @Test @@ -105,27 +106,27 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setPopulation(3444L); - Assert.assertEquals(3444L, location.getPopulation().longValue()); + assertEquals(3444L, location.getPopulation().longValue()); } @Test public void whenCallToString_thenAllIsFine() { final Location location = Location.withValues(44, "test"); - Assert.assertNotEquals("", location.toString()); + assertNotEquals("", location.toString()); - location.setCoordinate(Coordinate.withValues(33.2, 56.3)); + location.setCoordinate(Coordinate.of(33.2, 56.3)); - Assert.assertNotEquals("", location.toString()); + assertNotEquals("", location.toString()); location.setCountryCode("TN"); - Assert.assertNotEquals("", location.toString()); - Assert.assertNotNull(location.toString()); + assertNotEquals("", location.toString()); + assertNotNull(location.toString()); location.setPopulation(34343L); - Assert.assertNotEquals("", location.toString()); - Assert.assertNotNull(location.toString()); + assertNotEquals("", location.toString()); + assertNotNull(location.toString()); } @Test @@ -133,11 +134,11 @@ public class LocationUnitTest { final Location one = Location.withValues(44, "test"); final Location two = Location.withValues(44, "test"); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one.hashCode(), two.hashCode()); two.setName("112"); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test @@ -145,77 +146,77 @@ public class LocationUnitTest { final Location one = Location.withValues(44, "test"); final Location two = Location.withValues(44, "test"); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(new Object())); + assertEquals(one, one); + assertNotEquals(one, new Object()); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); two.setId(23); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); one.setId(23); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setName("23"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setName("23"); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setCountryCode("11"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setCountryCode("11"); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final LocalDateTime now = LocalDateTime.now(); - one.setSunrise(now); + one.setSunriseTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); - two.setSunrise(now); + two.setSunriseTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); - one.setSunset(now); + one.setSunsetTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); - two.setSunset(now); + two.setSunsetTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setZoneOffset(ZoneOffset.UTC); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setZoneOffset(ZoneOffset.UTC); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); - final Coordinate coordinate = Coordinate.withValues(33.5, -22.4); + final Coordinate coordinate = Coordinate.of(33.5, -22.4); one.setCoordinate(coordinate); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setCoordinate(coordinate); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setPopulation(20000L); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setPopulation(20000L); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/RainUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/RainUnitTest.java index 3105dd1..ffc6c98 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/RainUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/RainUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model.forecast; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class RainUnitTest { @Test @@ -32,34 +33,34 @@ public class RainUnitTest { Rain.withThreeHourLevelValue(0); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWithInvalidData_thenFail() { - Rain.withThreeHourLevelValue(-20); + assertThrows(IllegalArgumentException.class, () -> Rain.withThreeHourLevelValue(-20)); } @Test public void whenSetValues_thenTheyAreSet() { final Rain rain = Rain.withThreeHourLevelValue(0); - Assert.assertEquals(0, rain.getThreeHourRainLevel(), 0.00001); + assertEquals(0, rain.getThreeHourLevel(), 0.00001); - rain.setThreeHourRainLevel(55.5); - Assert.assertEquals(55.5, rain.getThreeHourRainLevel(), 0.00001); + rain.setThreeHourLevel(55.5); + assertEquals(55.5, rain.getThreeHourLevel(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidValue_thenFail() { final Rain rain = Rain.withThreeHourLevelValue(0); - rain.setThreeHourRainLevel(-20); + assertThrows(IllegalArgumentException.class, () -> rain.setThreeHourLevel(-20)); } @Test public void whenCallToString_thenAllIsFine() { final Rain rain = Rain.withThreeHourLevelValue(33.5); - Assert.assertNotNull(rain.toString()); - Assert.assertNotEquals("", rain.toString()); + assertNotNull(rain.toString()); + assertNotEquals("", rain.toString()); } @Test @@ -67,15 +68,15 @@ public class RainUnitTest { final Rain first = Rain.withThreeHourLevelValue(0); final Rain second = Rain.withThreeHourLevelValue(0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - second.setThreeHourRainLevel(11.0); + second.setThreeHourLevel(11.0); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - first.setThreeHourRainLevel(11.0); + first.setThreeHourLevel(11.0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test @@ -83,16 +84,16 @@ public class RainUnitTest { final Rain first = Rain.withThreeHourLevelValue(0); final Rain second = Rain.withThreeHourLevelValue(0); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); - second.setThreeHourRainLevel(66.7); + second.setThreeHourLevel(66.7); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - first.setThreeHourRainLevel(66.7); + first.setThreeHourLevel(66.7); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/SnowUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/SnowUnitTest.java index 6b5bf8d..a7037a4 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/SnowUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/SnowUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model.forecast; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class SnowUnitTest { @Test @@ -31,34 +32,34 @@ public class SnowUnitTest { Snow.withThreeHourLevelValue(2222.3); Snow.withThreeHourLevelValue(0); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWithInvalidData_thenFail() { - Snow.withThreeHourLevelValue(-20); + assertThrows(IllegalArgumentException.class, () -> Snow.withThreeHourLevelValue(-20)); } @Test public void whenSetValues_thenTheyAreSet() { final Snow snow = Snow.withThreeHourLevelValue(0); - Assert.assertEquals(0, snow.getThreeHourSnowLevel(), 0.00001); + assertEquals(0, snow.getThreeHourLevel(), 0.00001); - snow.setThreeHourSnowLevel(55.5); - Assert.assertEquals(55.5, snow.getThreeHourSnowLevel(), 0.00001); + snow.setThreeHourLevel(55.5); + assertEquals(55.5, snow.getThreeHourLevel(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidValue_thenFail() { final Snow snow = Snow.withThreeHourLevelValue(0); - snow.setThreeHourSnowLevel(-20); + assertThrows(IllegalArgumentException.class, () -> snow.setThreeHourLevel(-20)); } @Test public void whenCallToString_thenAllIsFine() { final Snow snow = Snow.withThreeHourLevelValue(33.5); - Assert.assertNotNull(snow.toString()); - Assert.assertNotEquals("", snow.toString()); + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); } @Test @@ -66,15 +67,15 @@ public class SnowUnitTest { final Snow first = Snow.withThreeHourLevelValue(0); final Snow second = Snow.withThreeHourLevelValue(0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - second.setThreeHourSnowLevel(11.0); + second.setThreeHourLevel(11.0); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - first.setThreeHourSnowLevel(11.0); + first.setThreeHourLevel(11.0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test @@ -82,16 +83,16 @@ public class SnowUnitTest { final Snow first = Snow.withThreeHourLevelValue(0); final Snow second = Snow.withThreeHourLevelValue(0); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); - second.setThreeHourSnowLevel(66.7); + second.setThreeHourLevel(66.7); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - first.setThreeHourSnowLevel(66.7); + first.setThreeHourLevel(66.7); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecastUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecastUnitTest.java index d0caceb..aee9951 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecastUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WeatherForecastUnitTest.java @@ -23,343 +23,287 @@ package com.github.prominence.openweathermap.api.model.forecast; import com.github.prominence.openweathermap.api.model.*; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; +import static org.junit.jupiter.api.Assertions.*; + public class WeatherForecastUnitTest { - @Test - public void whenCreateObjectWithValidArgs_thenObjectIsCreated() { - WeatherForecast.forValue("state", "desc"); - } - - @Test(expected = IllegalArgumentException.class) - public void whenCreateObjectWithoutState_thenThrowAnException() { - WeatherForecast.forValue(null, "desc"); - } - - @Test(expected = IllegalArgumentException.class) - public void whenCreateObjectWithoutDescription_thenThrowAnException() { - WeatherForecast.forValue("state", null); - } - - @Test - public void whenSetState_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); - weatherForecast.setState("test"); - - Assert.assertEquals("test", weatherForecast.getState()); - } - - @Test(expected = IllegalArgumentException.class) - public void whenSetNullState_thenThrowAnException() { - final WeatherForecast weather = WeatherForecast.forValue("state", "desc"); - weather.setState(null); - } - - @Test - public void whenSetDescription_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); - weatherForecast.setDescription("test"); - - Assert.assertEquals("test", weatherForecast.getDescription()); - } - - @Test(expected = IllegalArgumentException.class) - public void whenSetNullDescription_thenThrowAnException() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); - weatherForecast.setDescription(null); - } - - @Test - public void whenSetIconId_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); - Assert.assertNull(weatherForecast.getWeatherIconId()); - Assert.assertNull(weatherForecast.getWeatherIconUrl()); - - weatherForecast.setWeatherIconId("02n"); - - Assert.assertEquals("02n", weatherForecast.getWeatherIconId()); - Assert.assertNotNull(weatherForecast.getWeatherIconUrl()); - } - @Test public void whenSetForecastTime_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final LocalDateTime now = LocalDateTime.now(); weatherForecast.setForecastTime(now); - Assert.assertEquals(now, weatherForecast.getForecastTime()); + assertEquals(now, weatherForecast.getForecastTime()); } @Test public void whenSetTemperature_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Temperature temperature = Temperature.withValue(22.3, "a"); weatherForecast.setTemperature(temperature); - Assert.assertEquals(temperature, weatherForecast.getTemperature()); + assertEquals(temperature, weatherForecast.getTemperature()); } @Test public void whenSetPressure_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(33.2); weatherForecast.setAtmosphericPressure(atmosphericPressure); - Assert.assertEquals(atmosphericPressure, weatherForecast.getAtmosphericPressure()); + assertEquals(atmosphericPressure, weatherForecast.getAtmosphericPressure()); } @Test public void whenSetHumidity_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Humidity humidity = Humidity.withValue((byte) 44); weatherForecast.setHumidity(humidity); - Assert.assertEquals(humidity, weatherForecast.getHumidity()); + assertEquals(humidity, weatherForecast.getHumidity()); } @Test public void whenSetWind_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Wind wind = Wind.withValue(22.2, "a"); weatherForecast.setWind(wind); - Assert.assertEquals(wind, weatherForecast.getWind()); + assertEquals(wind, weatherForecast.getWind()); } @Test public void whenSetRain_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Rain rain = Rain.withThreeHourLevelValue(0); weatherForecast.setRain(rain); - Assert.assertEquals(rain, weatherForecast.getRain()); + assertEquals(rain, weatherForecast.getRain()); } @Test public void whenSetSnow_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Snow snow = Snow.withThreeHourLevelValue(0); weatherForecast.setSnow(snow); - Assert.assertEquals(snow, weatherForecast.getSnow()); + assertEquals(snow, weatherForecast.getSnow()); } @Test public void whenSetClouds_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Clouds clouds = Clouds.withValue((byte) 33); weatherForecast.setClouds(clouds); - Assert.assertEquals(clouds, weatherForecast.getClouds()); + assertEquals(clouds, weatherForecast.getClouds()); } @Test public void whenSetForecastTimeISO_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); - Assert.assertNull(weatherForecast.getForecastTimeISO()); + assertNull(weatherForecast.getForecastTimeISO()); weatherForecast.setForecastTimeISO("1994-2-3"); - Assert.assertEquals("1994-2-3", weatherForecast.getForecastTimeISO()); + assertEquals("1994-2-3", weatherForecast.getForecastTimeISO()); } @Test public void whenSetDayTime_thenValueIsSet() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); - Assert.assertNull(weatherForecast.getDayTime()); + assertNull(weatherForecast.getDayTime()); weatherForecast.setDayTime(DayTime.DAY); - Assert.assertEquals(DayTime.DAY, weatherForecast.getDayTime()); + assertEquals(DayTime.DAY, weatherForecast.getDayTime()); } @Test public void whenCallToString_thenAllIsFine() { - final WeatherForecast weatherForecast = WeatherForecast.forValue("state", "desc"); + final WeatherForecast weatherForecast = new WeatherForecast(); final Location location = Location.withValues(12312, "asd"); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); final Temperature temperature = Temperature.withValue(33.2, "asd"); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(44.4); final Clouds clouds = Clouds.withValue((byte) 55); final Rain rain = Rain.withThreeHourLevelValue(33.2); final Snow snow = Snow.withThreeHourLevelValue(33.1); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); + + weatherForecast.setWeatherState(weatherState); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); location.setCountryCode("3d"); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setTemperature(temperature); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setAtmosphericPressure(atmosphericPressure); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setClouds(clouds); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setRain(rain); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setSnow(snow); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setRain(null); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setSnow(null); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setRain(Rain.withThreeHourLevelValue(0)); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); weatherForecast.setSnow(Snow.withThreeHourLevelValue(0)); - Assert.assertNotEquals("", weatherForecast.toString()); - Assert.assertNotNull(weatherForecast.toString()); + assertNotEquals("", weatherForecast.toString()); + assertNotNull(weatherForecast.toString()); } @Test public void whenCallHashCode_thenAllIsFine() { - final WeatherForecast one = WeatherForecast.forValue("state", "desc"); - final WeatherForecast two = WeatherForecast.forValue("state", "desc"); + final WeatherForecast first = new WeatherForecast(); + final WeatherForecast second = new WeatherForecast(); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - two.setDescription("112"); + second.setDayTime(DayTime.NIGHT); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); } @Test public void whenCheckEquality_thenAllIsFine() { - final WeatherForecast one = WeatherForecast.forValue("state", "desc"); - final WeatherForecast two = WeatherForecast.forValue("state1", "desc1"); + final WeatherForecast first = new WeatherForecast(); + final WeatherForecast second = new WeatherForecast(); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(null)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertFalse(one.equals(two)); - - two.setState("state"); - - Assert.assertFalse(one.equals(two)); - - two.setDescription("desc"); - - Assert.assertTrue(one.equals(two)); - - one.setWeatherIconId("1"); - - Assert.assertFalse(one.equals(two)); - - two.setWeatherIconId("1"); - - Assert.assertTrue(one.equals(two)); + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + assertEquals(first, second); final LocalDateTime now = LocalDateTime.now(); - one.setForecastTime(now); + first.setForecastTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setForecastTime(now); + second.setForecastTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Temperature temperature = Temperature.withValue(33.2, "as"); - one.setTemperature(temperature); + first.setTemperature(temperature); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setTemperature(temperature); + second.setTemperature(temperature); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(33.33); - one.setAtmosphericPressure(atmosphericPressure); + first.setAtmosphericPressure(atmosphericPressure); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setAtmosphericPressure(atmosphericPressure); + second.setAtmosphericPressure(atmosphericPressure); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Humidity humidity = Humidity.withValue((byte) 33); - one.setHumidity(humidity); + first.setHumidity(humidity); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setHumidity(humidity); + second.setHumidity(humidity); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Wind wind = Wind.withValue(33.6, "asd"); - one.setWind(wind); + first.setWind(wind); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setWind(wind); + second.setWind(wind); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Rain rain = Rain.withThreeHourLevelValue(0); - one.setRain(rain); + first.setRain(rain); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setRain(rain); + second.setRain(rain); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Snow snow = Snow.withThreeHourLevelValue(0); - one.setSnow(snow); + first.setSnow(snow); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setSnow(snow); + second.setSnow(snow); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); final Clouds clouds = Clouds.withValue((byte) 33); - one.setClouds(clouds); + first.setClouds(clouds); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setClouds(clouds); + second.setClouds(clouds); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); - one.setForecastTimeISO("test"); + first.setForecastTimeISO("test"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setForecastTimeISO("test"); + second.setForecastTimeISO("test"); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); - one.setDayTime(DayTime.NIGHT); + first.setDayTime(DayTime.NIGHT); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - two.setDayTime(DayTime.DAY); + second.setDayTime(DayTime.DAY); - Assert.assertFalse(one.equals(two)); + assertNotEquals(first, second); - one.setDayTime(DayTime.DAY); + first.setDayTime(DayTime.DAY); - Assert.assertTrue(one.equals(two)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WindUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WindUnitTest.java index 41697c4..5c58871 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WindUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/forecast/WindUnitTest.java @@ -22,108 +22,109 @@ package com.github.prominence.openweathermap.api.model.forecast; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class WindUnitTest { @Test public void whenCreateWindWithValidArgs_thenValueIsSet() { - Assert.assertEquals(44.0, Wind.withValue(44, "ms").getSpeed(), 0.00001); + assertEquals(44.0, Wind.withValue(44, "ms").getSpeed(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWindWithInvalidSpeedArg_thenThrowAnException() { - Wind.withValue(-21, "a"); + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(-21, "a")); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWindWithInvalidUnitArg_thenThrowAnException() { - Wind.withValue(342, null); + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(342, null)); } @Test public void whenSetValidSpeed_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(33, wind.getSpeed(), 0.00001); + assertEquals(33, wind.getSpeed(), 0.00001); wind.setSpeed(0); - Assert.assertEquals(0, wind.getSpeed(), 0.00001); + assertEquals(0, wind.getSpeed(), 0.00001); wind.setSpeed(3656); - Assert.assertEquals(3656, wind.getSpeed(), 0.00001); + assertEquals(3656, wind.getSpeed(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidSpeedBelow0_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(33, wind.getSpeed(), 0.00001); + assertEquals(33, wind.getSpeed(), 0.00001); - wind.setSpeed(-22); + assertThrows(IllegalArgumentException.class, () -> wind.setSpeed(-22)); } @Test public void whenSetValidDegrees_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertNull(wind.getDegrees()); + assertNull(wind.getDegrees()); wind.setDegrees(22); - Assert.assertEquals(22, wind.getDegrees(), 0.00001); + assertEquals(22, wind.getDegrees(), 0.00001); wind.setDegrees(0); - Assert.assertEquals(0, wind.getDegrees(), 0.00001); + assertEquals(0, wind.getDegrees(), 0.00001); wind.setDegrees(360); - Assert.assertEquals(360, wind.getDegrees(), 0.00001); + assertEquals(360, wind.getDegrees(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidDegreesBelow0_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setDegrees(-32); + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(-32)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidDegreesAbove360_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setDegrees(378); + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(378)); } @Test public void whenSetNonNullUnit_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(wind.getUnit(), "as"); + assertEquals(wind.getUnit(), "as"); wind.setUnit("myUnit"); - Assert.assertEquals(wind.getUnit(), "myUnit"); + assertEquals(wind.getUnit(), "myUnit"); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetNullUnit_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setUnit(null); + assertThrows(IllegalArgumentException.class, () -> wind.setUnit(null)); } @Test public void whenCallToString_thenAllIsFine() { final Wind wind = Wind.withValue(302, "a"); - Assert.assertNotNull(wind.toString()); + assertNotNull(wind.toString()); wind.setDegrees(22); - Assert.assertNotNull(wind.toString()); - Assert.assertNotEquals("", wind.toString()); + assertNotNull(wind.toString()); + assertNotEquals("", wind.toString()); } @Test @@ -131,49 +132,55 @@ public class WindUnitTest { final Wind first = Wind.withValue(22, "a"); final Wind second = Wind.withValue(22, "b"); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); second.setUnit("a"); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); second.setSpeed(33); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); first.setSpeed(333); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); first.setSpeed(33); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test public void whenCheckEquality_thenAllIsFine() { final Wind first = Wind.withValue(11, "a"); - final Wind second = Wind.withValue(11, "a"); + final Wind second = Wind.withValue(12, "a"); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertNotEquals(first, second); + first.setSpeed(12); + + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); first.setDegrees(34); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); second.setDegrees(34); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); second.setUnit("v"); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first.setUnit("v"); + + assertEquals(first, second); + first.setSpeed(second.getSpeed() + 4); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressureUnitTest.java new file mode 100644 index 0000000..64e1a67 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/AtmosphericPressureUnitTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class AtmosphericPressureUnitTest { + @Test + public void withInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> AtmosphericPressure.withValue(-20.0)); + } + + @Test + public void getSeaLevelValue() { + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.2); + + assertEquals(22.2, atmosphericPressure.getSeaLevelValue(), 0.00001); + } + + @Test + public void getUnit() { + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.2); + + assertNotNull(atmosphericPressure.getUnit()); + assertNotEquals("", atmosphericPressure.getUnit()); + } + + @Test + public void testEquals() { + final AtmosphericPressure first = AtmosphericPressure.withValue(600); + final AtmosphericPressure second = AtmosphericPressure.withValue(600); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + first.setSeaLevelValue(200); + + assertNotEquals(first, second); + } + + @Test + public void testHashCode() { + final AtmosphericPressure first = AtmosphericPressure.withValue(600); + final AtmosphericPressure second = AtmosphericPressure.withValue(600); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setSeaLevelValue(200); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.2); + + assertNotNull(atmosphericPressure.toString()); + assertNotEquals("", atmosphericPressure.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/CurrentUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/CurrentUnitTest.java new file mode 100644 index 0000000..196af22 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/CurrentUnitTest.java @@ -0,0 +1,335 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class CurrentUnitTest { + @Test + public void getForecastTime() { + final Current current = new Current(); + final LocalDateTime now = LocalDateTime.now(); + current.setForecastTime(now); + + assertEquals(now, current.getForecastTime()); + } + + @Test + public void getSunriseTime() { + final Current current = new Current(); + final LocalDateTime now = LocalDateTime.now(); + current.setSunriseTime(now); + + assertEquals(now, current.getSunriseTime()); + } + + @Test + public void getSunsetTime() { + final Current current = new Current(); + final LocalDateTime now = LocalDateTime.now(); + current.setSunsetTime(now); + + assertEquals(now, current.getSunsetTime()); + } + + @Test + public void getWeatherState() { + final Current current = new Current(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + current.setWeatherState(weatherState); + + assertEquals(weatherState, current.getWeatherState()); + } + + @Test + public void getTemperature() { + final Current current = new Current(); + final Temperature temperature = Temperature.withValue(10, "K"); + + current.setTemperature(temperature); + + assertEquals(temperature, current.getTemperature()); + } + + @Test + public void getAtmosphericPressure() { + final Current current = new Current(); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + current.setAtmosphericPressure(atmosphericPressure); + + assertEquals(atmosphericPressure, current.getAtmosphericPressure()); + } + + @Test + public void getHumidity() { + final Current current = new Current(); + final Humidity humidity = Humidity.withValue((byte) 10); + current.setHumidity(humidity); + + assertEquals(humidity, current.getHumidity()); + } + + @Test + public void getWind() { + final Current current = new Current(); + final Wind wind = Wind.withValue(13.2, "m/s"); + current.setWind(wind); + + assertEquals(wind, current.getWind()); + } + + @Test + public void getClouds() { + final Current current = new Current(); + final Clouds clouds = Clouds.withValue((byte) 25); + current.setClouds(clouds); + + assertEquals(clouds, current.getClouds()); + } + + @Test + public void getUvIndex() { + final Current current = new Current(); + final double uvIndex = 22.4; + current.setUvIndex(uvIndex); + + assertEquals(uvIndex, current.getUvIndex(), 0.00001); + + current.setUvIndex(null); + + assertNull(current.getUvIndex()); + } + + @Test + public void getIllegalUvIndexValue() { + final Current current = new Current(); + + assertThrows(IllegalArgumentException.class, () -> current.setUvIndex(-1.2)); + } + + @Test + public void getProbabilityOfPrecipitation() { + final Current current = new Current(); + final double vim = 120; + current.setVisibilityInMetres(vim); + + assertEquals(vim, current.getVisibilityInMetres(), 0.00001); + + current.setVisibilityInMetres(null); + + assertNull(current.getVisibilityInMetres()); + } + + @Test + public void getIllegalProbabilityOfPrecipitationValue_negative() { + final Current current = new Current(); + + assertThrows(IllegalArgumentException.class, () -> current.setVisibilityInMetres(-20.0)); + } + + @Test + public void getRain() { + final Current current = new Current(); + final Rain rain = Rain.withOneHourLevelValue(20.2); + current.setRain(rain); + + assertEquals(rain, current.getRain()); + } + + @Test + public void getSnow() { + final Current current = new Current(); + final Snow snow = Snow.withOneHourLevelValue(25.0); + current.setSnow(snow); + + assertEquals(snow, current.getSnow()); + } + + @Test + public void getEquals() { + final LocalDateTime now = LocalDateTime.now(); + final Current first = new Current(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final Current second = new Current(); + + assertEquals(first, second); + + first.setForecastTime(now); + + assertNotEquals(first, second); + + second.setForecastTime(now); + + assertEquals(first, second); + + first.setSunriseTime(now); + + assertNotEquals(first, second); + + second.setSunriseTime(now); + + assertEquals(first, second); + + first.setSunsetTime(now); + + assertNotEquals(first, second); + + second.setSunsetTime(now); + + assertEquals(first, second); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); + + final Temperature temperature = Temperature.withValue(10, "K"); + + first.setTemperature(temperature); + + assertNotEquals(first, second); + + second.setTemperature(temperature); + + assertEquals(first, second); + + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + + first.setAtmosphericPressure(atmosphericPressure); + + assertNotEquals(first, second); + + second.setAtmosphericPressure(atmosphericPressure); + + assertEquals(first, second); + + final Humidity humidity = Humidity.withValue((byte) 10); + + first.setHumidity(humidity); + + assertNotEquals(first, second); + + second.setHumidity(humidity); + + assertEquals(first, second); + + final Wind wind = Wind.withValue(13.2, "m/s"); + + first.setWind(wind); + + assertNotEquals(first, second); + + second.setWind(wind); + + assertEquals(first, second); + + final Clouds clouds = Clouds.withValue((byte) 25); + + first.setClouds(clouds); + + assertNotEquals(first, second); + + second.setClouds(clouds); + + assertEquals(first, second); + + final double uvIndex = 22.4; + + first.setUvIndex(uvIndex); + + assertNotEquals(first, second); + + second.setUvIndex(uvIndex); + + assertEquals(first, second); + + final double vim = 250; + + first.setVisibilityInMetres(vim); + + assertNotEquals(first, second); + + second.setVisibilityInMetres(vim); + + assertEquals(first, second); + + final Rain rain = Rain.withOneHourLevelValue(20.2); + + first.setRain(rain); + + assertNotEquals(first, second); + + second.setRain(rain); + + assertEquals(first, second); + + final Snow snow = Snow.withOneHourLevelValue(25.0); + + first.setSnow(snow); + + assertNotEquals(first, second); + + second.setSnow(snow); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final Current first = new Current(); + final Current second = new Current(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setForecastTime(LocalDateTime.now()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final LocalDateTime now = LocalDateTime.now(); + final Current current = new Current(); + + current.setForecastTime(now); + + assertNotNull(current.toString()); + assertNotEquals("", current.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/RainUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/RainUnitTest.java new file mode 100644 index 0000000..2244432 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/RainUnitTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class RainUnitTest { + @Test + public void withInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> Rain.withOneHourLevelValue(-20.0)); + } + + @Test + public void getOneHourRainLevel() { + final Rain rain = Rain.withOneHourLevelValue(220.0); + + assertEquals(220.0, rain.getOneHourLevel(), 0.00001); + } + + @Test + public void getUnit() { + final Rain rain = Rain.withOneHourLevelValue(220.0); + + assertNotNull(rain.getUnit()); + assertNotEquals("", rain.getUnit()); + } + + @Test + public void testEquals() { + final Rain first = Rain.withOneHourLevelValue(600); + final Rain second = Rain.withOneHourLevelValue(600); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + first.setOneHourLevel(200); + + assertNotEquals(first, second); + } + + @Test + public void testHashCode() { + final Rain first = Rain.withOneHourLevelValue(600); + final Rain second = Rain.withOneHourLevelValue(600); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setOneHourLevel(200); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Rain rain = Rain.withOneHourLevelValue(22.2); + + assertNotNull(rain.toString()); + assertNotEquals("", rain.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/SnowUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/SnowUnitTest.java new file mode 100644 index 0000000..38bb658 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/SnowUnitTest.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class SnowUnitTest { + @Test + public void withInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> Snow.withOneHourLevelValue(-20.0)); + } + + @Test + public void getOneHourRainLevel() { + final Snow snow = Snow.withOneHourLevelValue(220.0); + + assertEquals(220.0, snow.getOneHourLevel(), 0.00001); + } + + @Test + public void getUnit() { + final Snow snow = Snow.withOneHourLevelValue(220.0); + + assertNotNull(snow.getUnit()); + assertNotEquals("", snow.getUnit()); + } + + @Test + public void testEquals() { + final Snow first = Snow.withOneHourLevelValue(600); + final Snow second = Snow.withOneHourLevelValue(600); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + first.setOneHourLevel(200); + + assertNotEquals(first, second); + } + + @Test + public void testHashCode() { + final Snow first = Snow.withOneHourLevelValue(600); + final Snow second = Snow.withOneHourLevelValue(600); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setOneHourLevel(200); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Snow snow = Snow.withOneHourLevelValue(22.2); + + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/TemperatureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/TemperatureUnitTest.java new file mode 100644 index 0000000..de24ea2 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/TemperatureUnitTest.java @@ -0,0 +1,129 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class TemperatureUnitTest { + @Test + public void withInvalidValue_noUnit() { + assertThrows(IllegalArgumentException.class, () -> Temperature.withValue(-20, null)); + } + + @Test + public void getValue() { + final Temperature temperature = Temperature.withValue(20, "K"); + + assertEquals(20, temperature.getValue(), 0.00001); + } + + @Test + public void getFeelsLike() { + final Temperature temperature = Temperature.withValue(20, "K"); + temperature.setFeelsLike(18.0); + + assertEquals(18.0, temperature.getFeelsLike(), 0.00001); + } + + @Test + public void getDewPoint() { + final Temperature temperature = Temperature.withValue(20, "K"); + temperature.setDewPoint(5.0); + + assertEquals(5.0, temperature.getDewPoint(), 0.00001); + } + + @Test + public void getUnit() { + final Temperature temperature = Temperature.withValue(20, "K"); + + assertEquals("K", temperature.getUnit()); + } + + @Test + public void testEquals() { + final Temperature first = Temperature.withValue(30, "L"); + final Temperature second = Temperature.withValue(30, "K"); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertNotEquals(first, second); + + first.setUnit("K"); + + assertEquals(first, second); + + first.setFeelsLike(25.0); + + assertNotEquals(first, second); + + second.setFeelsLike(25.0); + + assertEquals(first, second); + + first.setDewPoint(10.0); + + assertNotEquals(first, second); + + second.setDewPoint(10.0); + + assertEquals(first, second); + + first.setValue(27.0); + + assertNotEquals(first, second); + + second.setValue(27.0); + + assertEquals(first, second); + } + + @Test + public void testHashCode() { + final Temperature first = Temperature.withValue(600, "K"); + final Temperature second = Temperature.withValue(600, "K"); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setFeelsLike(599d); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Temperature temperature = Temperature.withValue(20, "K"); + + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); + + temperature.setFeelsLike(22.4); + + assertNotNull(temperature.toString()); + assertNotEquals("", temperature.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java new file mode 100644 index 0000000..61c0acc --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/WindUnitTest.java @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class WindUnitTest { + @Test + public void withInvalidValue_noUnit() { + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(20, null)); + } + + @Test + public void withInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(-20, "m/s")); + } + + @Test + public void getSpeed() { + final Wind wind = Wind.withValue(20, "m/s"); + + assertEquals(20.0, wind.getSpeed(), 0.00001); + } + + @Test + public void getGust() { + final Wind wind = Wind.withValue(20, "m/s"); + wind.setGust(40); + + assertEquals(40.0, wind.getGust(), 0.00001); + } + + @Test + public void setGust_negative() { + final Wind wind = Wind.withValue(20, "m/s"); + + assertThrows(IllegalArgumentException.class, () -> wind.setGust(-20)); + } + + @Test + public void getDegrees() { + final Wind wind = Wind.withValue(20, "m/s"); + wind.setDegrees(180); + + assertEquals(180.0, wind.getDegrees(), 0.00001); + } + + @Test + public void setDegrees_lessThanZero() { + final Wind wind = Wind.withValue(20, "m/s"); + + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(-20)); + } + + @Test + public void setDegrees_moreThan360() { + final Wind wind = Wind.withValue(20, "m/s"); + + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(420)); + } + + @Test + public void getUnit() { + final Wind wind = Wind.withValue(20, "m/s"); + + assertEquals("m/s", wind.getUnit()); + } + + @Test + public void testEquals() { + final Wind first = Wind.withValue(40, "m/s"); + final Wind second = Wind.withValue(40, "m/s"); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + first.setSpeed(20); + + assertNotEquals(first, second); + + second.setSpeed(20); + + assertEquals(first, second); + + first.setDegrees(10); + + assertNotEquals(first, second); + + second.setDegrees(10); + + assertEquals(first, second); + + first.setGust(30); + + assertNotEquals(first, second); + + second.setGust(30); + + assertEquals(first, second); + + second.setUnit("km/h"); + + assertNotEquals(first, second); + } + + @Test + public void testHashCode() { + final Wind first = Wind.withValue(40, "m/s"); + final Wind second = Wind.withValue(40, "m/s"); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setGust(30); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Wind wind = Wind.withValue(40, "m/s"); + + assertNotNull(wind.toString()); + assertNotEquals("", wind.toString()); + + wind.setGust(20); + + assertNotNull(wind.toString()); + assertNotEquals("", wind.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/AlertUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/AlertUnitTest.java new file mode 100644 index 0000000..bcbd3d0 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/AlertUnitTest.java @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; +import java.time.temporal.ChronoUnit; + +import static org.junit.jupiter.api.Assertions.*; + +public class AlertUnitTest { + @Test + public void getSenderName() { + final Alert alert = new Alert(); + alert.setSenderName("Sender"); + + assertEquals("Sender", alert.getSenderName()); + } + + @Test + public void getEventName() { + final Alert alert = new Alert(); + alert.setEventName("Event"); + + assertEquals("Event", alert.getEventName()); + } + + @Test + public void getStartTime() { + final Alert alert = new Alert(); + final LocalDateTime now = LocalDateTime.now(); + alert.setStartTime(now); + + assertEquals(now, alert.getStartTime()); + } + + @Test + public void getEndTime() { + final Alert alert = new Alert(); + final LocalDateTime now = LocalDateTime.now(); + alert.setEndTime(now); + + assertEquals(now, alert.getEndTime()); + } + + @Test + public void getDescription() { + final Alert alert = new Alert(); + alert.setDescription("Description"); + + assertEquals("Description", alert.getDescription()); + } + + @Test + public void getEquals() { + final Alert first = new Alert(); + final Alert second = new Alert(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final String sender = "Sender"; + final String event = "Event"; + final String description = "Description"; + final LocalDateTime now = LocalDateTime.now(); + + assertEquals(first, second); + + first.setSenderName(sender); + + assertNotEquals(first, second); + + second.setSenderName(sender); + + assertEquals(first, second); + + first.setEventName(event); + + assertNotEquals(first, second); + + second.setEventName(event); + + assertEquals(first, second); + + first.setStartTime(now); + + assertNotEquals(first, second); + + second.setStartTime(now); + + assertEquals(first, second); + + first.setEndTime(now); + + assertNotEquals(first, second); + + second.setEndTime(now); + + assertEquals(first, second); + + first.setDescription(description); + + assertNotEquals(first, second); + + second.setDescription(description); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final Alert event1 = new Alert("Sender", "Event1", LocalDateTime.now(), LocalDateTime.now().plus(2, ChronoUnit.HOURS), "Description1"); + final Alert event2 = new Alert("Sender", "Event2", LocalDateTime.now(), LocalDateTime.now().plus(2, ChronoUnit.HOURS), "Description2"); + + assertEquals(event1.hashCode(), event1.hashCode()); + assertNotEquals(event1.hashCode(), event2.hashCode()); + } + + @Test + public void getToString() { + final Alert alert = new Alert("Sender", "Event", LocalDateTime.now(), LocalDateTime.now().plus(2, ChronoUnit.HOURS), "Description"); + + assertNotNull(alert.toString()); + assertNotEquals("", alert.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherDataUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherDataUnitTest.java new file mode 100644 index 0000000..811fca6 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/CurrentWeatherDataUnitTest.java @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.model.onecall.Current; +import org.junit.jupiter.api.Test; + +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CurrentWeatherDataUnitTest { + @Test + public void getCoordinate() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final Coordinate coordinate = Coordinate.of(11.2, 43.2); + currentWeatherData.setCoordinate(coordinate); + + assertEquals(coordinate, currentWeatherData.getCoordinate()); + } + + @Test + public void getTimezone() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final ZoneId timeZone = ZoneId.of("GMT"); + currentWeatherData.setTimezone(timeZone); + + assertEquals(timeZone, currentWeatherData.getTimezone()); + } + + @Test + public void getTimezoneOffset() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final ZoneOffset offset = ZoneOffset.UTC; + currentWeatherData.setTimezoneOffset(offset); + + assertEquals(offset, currentWeatherData.getTimezoneOffset()); + } + + @Test + public void getCurrent() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final Current current = new Current(); + currentWeatherData.setCurrent(current); + + assertEquals(current, currentWeatherData.getCurrent()); + } + + @Test + public void getMinutelyList() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final List minutelyList = new ArrayList<>(); + currentWeatherData.setMinutelyList(minutelyList); + + assertEquals(minutelyList, currentWeatherData.getMinutelyList()); + } + + @Test + public void getHourlyList() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final List hourlyList = new ArrayList<>(); + currentWeatherData.setHourlyList(hourlyList); + + assertEquals(hourlyList, currentWeatherData.getHourlyList()); + } + + @Test + public void getDailyList() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final List dailyList = new ArrayList<>(); + currentWeatherData.setDailyList(dailyList); + + assertEquals(dailyList, currentWeatherData.getDailyList()); + } + + @Test + public void getAlerts() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + final List alerts = new ArrayList<>(); + currentWeatherData.setAlerts(alerts); + + assertEquals(alerts, currentWeatherData.getAlerts()); + } + + @Test + public void getEquals() { + final CurrentWeatherData first = new CurrentWeatherData(); + final CurrentWeatherData second = new CurrentWeatherData(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final Coordinate coordinate = Coordinate.of(11, 12); + final ZoneId timeZone = ZoneId.of("GMT"); + final ZoneOffset offset = ZoneOffset.UTC; + final Current current = new Current(); + final List minutelyList = new ArrayList<>(); + final List hourlyList = new ArrayList<>(); + final List dailyList = new ArrayList<>(); + final List alerts = new ArrayList<>(); + + assertEquals(first, second); + + first.setCoordinate(coordinate); + + assertNotEquals(first, second); + + second.setCoordinate(coordinate); + + assertEquals(first, second); + + first.setTimezone(timeZone); + + assertNotEquals(first, second); + + second.setTimezone(timeZone); + + assertEquals(first, second); + + first.setTimezoneOffset(offset); + + assertNotEquals(first, second); + + second.setTimezoneOffset(offset); + + assertEquals(first, second); + + first.setCurrent(current); + + assertNotEquals(first, second); + + second.setCurrent(current); + + assertEquals(first, second); + + first.setMinutelyList(minutelyList); + + assertNotEquals(first, second); + + second.setMinutelyList(minutelyList); + + assertEquals(first, second); + + first.setHourlyList(hourlyList); + + assertNotEquals(first, second); + + second.setHourlyList(hourlyList); + + assertEquals(first, second); + + first.setDailyList(dailyList); + + assertNotEquals(first, second); + + second.setDailyList(dailyList); + + assertEquals(first, second); + + first.setAlerts(alerts); + + assertNotEquals(first, second); + + second.setAlerts(alerts); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final CurrentWeatherData first = new CurrentWeatherData(); + final CurrentWeatherData second = new CurrentWeatherData(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setCoordinate(Coordinate.of(11, 42)); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final CurrentWeatherData currentWeatherData = new CurrentWeatherData(); + currentWeatherData.setCoordinate(Coordinate.of(32, 22)); + + assertNotNull(currentWeatherData.toString()); + assertNotEquals("", currentWeatherData.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRainUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRainUnitTest.java new file mode 100644 index 0000000..384a223 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyRainUnitTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class DailyRainUnitTest { + @Test + public void getValue() { + final DailyRain dailyRain = DailyRain.withValue(20); + + assertEquals(20, dailyRain.getValue(), 0.00001); + } + + @Test + public void getInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> DailyRain.withValue(-20)); + } + + @Test + public void getUnit() { + final DailyRain dailyRain = DailyRain.withValue(20); + + assertNotNull(dailyRain.getUnit()); + assertNotEquals("", dailyRain.getUnit()); + } + + @Test + public void getEquals() { + final DailyRain first = DailyRain.withValue(0); + final DailyRain second = DailyRain.withValue(0); + + assertEquals(first, second); + + first.setValue(20); + + assertNotEquals(first, second); + } + + @Test + public void getHashCode() { + final DailyRain first = DailyRain.withValue(0); + final DailyRain second = DailyRain.withValue(0); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setValue(20); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final DailyRain dailyRain = DailyRain.withValue(20); + + assertNotNull(dailyRain.toString()); + assertNotEquals("", dailyRain.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnowUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnowUnitTest.java new file mode 100644 index 0000000..ec4f51a --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailySnowUnitTest.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class DailySnowUnitTest { + @Test + public void getValue() { + final DailySnow dailySnow = DailySnow.withValue(20); + + assertEquals(20, dailySnow.getValue(), 0.00001); + } + + @Test + public void getInvalidValue_negative() { + assertThrows(IllegalArgumentException.class, () -> DailySnow.withValue(-20)); + } + + @Test + public void getUnit() { + final DailySnow dailySnow = DailySnow.withValue(20); + + assertNotNull(dailySnow.getUnit()); + assertNotEquals("", dailySnow.getUnit()); + } + + @Test + public void getEquals() { + final DailySnow first = DailySnow.withValue(0); + final DailySnow second = DailySnow.withValue(0); + + assertEquals(first, second); + + first.setValue(20); + + assertNotEquals(first, second); + } + + @Test + public void getHashCode() { + final DailySnow first = DailySnow.withValue(0); + final DailySnow second = DailySnow.withValue(0); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setValue(20); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final DailySnow dailySnow = DailySnow.withValue(20); + + assertNotNull(dailySnow.toString()); + assertNotEquals("", dailySnow.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java new file mode 100644 index 0000000..93dfb91 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyTemperatureUnitTest.java @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class DailyTemperatureUnitTest { + + @Test + public void getMorning() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setMorning(value); + + assertEquals(value, temperature.getMorning(), 0.00001); + } + + @Test + public void getMorningFeelsLike() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setMorningFeelsLike(value); + + assertEquals(value, temperature.getMorningFeelsLike(), 0.00001); + } + + @Test + public void getDay() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setDay(value); + + assertEquals(value, temperature.getDay(), 0.00001); + } + + @Test + public void getDayFeelsLike() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setDayFeelsLike(value); + + assertEquals(value, temperature.getDayFeelsLike(), 0.00001); + } + + @Test + public void getEve() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setEve(value); + + assertEquals(value, temperature.getEve(), 0.00001); + } + + @Test + public void getEveFeelsLike() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setEveFeelsLike(value); + + assertEquals(value, temperature.getEveFeelsLike(), 0.00001); + } + + @Test + public void getNight() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setNight(value); + + assertEquals(value, temperature.getNight(), 0.00001); + } + + @Test + public void getNightFeelsLike() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setNightFeelsLike(value); + + assertEquals(value, temperature.getNightFeelsLike(), 0.00001); + } + + @Test + public void getMin() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setMin(value); + + assertEquals(value, temperature.getMin(), 0.00001); + } + + @Test + public void getMax() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setMax(value); + + assertEquals(value, temperature.getMax(), 0.00001); + } + + @Test + public void getDewPoint() { + final DailyTemperature temperature = new DailyTemperature(); + final double value = 20.0; + temperature.setDewPoint(value); + + assertEquals(value, temperature.getDewPoint(), 0.00001); + } + + @Test + public void getUnit() { + final DailyTemperature temperature = new DailyTemperature(); + temperature.setUnit("T"); + + assertEquals("T", temperature.getUnit()); + } + + @Test + public void getEquals() { + final DailyTemperature first = new DailyTemperature(); + final DailyTemperature second = new DailyTemperature(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, second); + + first.setMorning(1.0); + + assertNotEquals(first, second); + + second.setMorning(1.0); + + assertEquals(first, second); + + first.setMorningFeelsLike(2.0); + + assertNotEquals(first, second); + + second.setMorningFeelsLike(2.0); + + assertEquals(first, second); + + first.setDay(3.0); + + assertNotEquals(first, second); + + second.setDay(3.0); + + assertEquals(first, second); + + first.setDayFeelsLike(4.0); + + assertNotEquals(first, second); + + second.setDayFeelsLike(4.0); + + assertEquals(first, second); + + first.setEve(5.0); + + assertNotEquals(first, second); + + second.setEve(5.0); + + assertEquals(first, second); + + first.setEveFeelsLike(6.0); + + assertNotEquals(first, second); + + second.setEveFeelsLike(6.0); + + assertEquals(first, second); + + first.setNight(7.0); + + assertNotEquals(first, second); + + second.setNight(7.0); + + assertEquals(first, second); + + first.setNightFeelsLike(8.0); + + assertNotEquals(first, second); + + second.setNightFeelsLike(8.0); + + assertEquals(first, second); + + first.setDewPoint(9.0); + + assertNotEquals(first, second); + + second.setDewPoint(9.0); + + assertEquals(first, second); + + first.setMin(10.0); + + assertNotEquals(first, second); + + second.setMin(10.0); + + assertEquals(first, second); + + first.setMax(11.0); + + assertNotEquals(first, second); + + second.setMax(11.0); + + assertEquals(first, second); + + first.setUnit("K"); + + assertNotEquals(first, second); + + second.setUnit("K"); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final DailyTemperature first = new DailyTemperature(); + final DailyTemperature second = new DailyTemperature(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setUnit("K"); + + assertNotEquals(first.hashCode(), second.hashCode()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java new file mode 100644 index 0000000..8df245b --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/DailyUnitTest.java @@ -0,0 +1,395 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.AtmosphericPressure; +import com.github.prominence.openweathermap.api.model.onecall.Wind; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class DailyUnitTest { + @Test + public void getForecastTime() { + final Daily daily = new Daily(); + final LocalDateTime now = LocalDateTime.now(); + daily.setForecastTime(now); + + assertEquals(now, daily.getForecastTime()); + } + + @Test + public void getSunriseTime() { + final Daily daily = new Daily(); + final LocalDateTime now = LocalDateTime.now(); + daily.setSunriseTime(now); + + assertEquals(now, daily.getSunriseTime()); + } + + @Test + public void getSunsetTime() { + final Daily daily = new Daily(); + final LocalDateTime now = LocalDateTime.now(); + daily.setSunsetTime(now); + + assertEquals(now, daily.getSunsetTime()); + } + + @Test + public void getWeatherState() { + final Daily daily = new Daily(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + daily.setWeatherState(weatherState); + + assertEquals(weatherState, daily.getWeatherState()); + } + + @Test + public void getTemperature() { + final Daily daily = new Daily(); + final DailyTemperature dailyTemperature = new DailyTemperature(); + dailyTemperature.setDay(10.0); + dailyTemperature.setEveFeelsLike(44.2); + + daily.setTemperature(dailyTemperature); + + assertEquals(dailyTemperature, daily.getTemperature()); + } + + @Test + public void getAtmosphericPressure() { + final Daily daily = new Daily(); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + daily.setAtmosphericPressure(atmosphericPressure); + + assertEquals(atmosphericPressure, daily.getAtmosphericPressure()); + } + + @Test + public void getHumidity() { + final Daily daily = new Daily(); + final Humidity humidity = Humidity.withValue((byte) 10); + daily.setHumidity(humidity); + + assertEquals(humidity, daily.getHumidity()); + } + + @Test + public void getWind() { + final Daily daily = new Daily(); + final Wind wind = Wind.withValue(13.2, "m/s"); + daily.setWind(wind); + + assertEquals(wind, daily.getWind()); + } + + @Test + public void getClouds() { + final Daily daily = new Daily(); + final Clouds clouds = Clouds.withValue((byte) 25); + daily.setClouds(clouds); + + assertEquals(clouds, daily.getClouds()); + } + + @Test + public void getUvIndex() { + final Daily daily = new Daily(); + final double uvIndex = 22.4; + daily.setUvIndex(uvIndex); + + assertEquals(uvIndex, daily.getUvIndex(), 0.00001); + + daily.setUvIndex(null); + + assertNull(daily.getUvIndex()); + } + + @Test + public void getIllegalUvIndexValue() { + final Daily daily = new Daily(); + + assertThrows(IllegalArgumentException.class, () -> daily.setUvIndex(-1.2)); + } + + @Test + public void getProbabilityOfPrecipitation() { + final Daily daily = new Daily(); + final double pop = 70.5; + daily.setProbabilityOfPrecipitation(pop); + + assertEquals(pop, daily.getProbabilityOfPrecipitation(), 0.00001); + + daily.setProbabilityOfPrecipitation(null); + + assertNull(daily.getProbabilityOfPrecipitation()); + } + + @Test + public void getIllegalProbabilityOfPrecipitationValue_negative() { + final Daily daily = new Daily(); + + assertThrows(IllegalArgumentException.class, () -> daily.setProbabilityOfPrecipitation(-20.0)); + } + + @Test + public void getIllegalProbabilityOfPrecipitationValue_tooBig() { + final Daily daily = new Daily(); + + assertThrows(IllegalArgumentException.class, () -> daily.setProbabilityOfPrecipitation(120.0)); + } + + @Test + public void getRain() { + final Daily daily = new Daily(); + final DailyRain rain = DailyRain.withValue(20.2); + daily.setRain(rain); + + assertEquals(rain, daily.getRain()); + } + + @Test + public void getSnow() { + final Daily daily = new Daily(); + final DailySnow snow = DailySnow.withValue(25.0); + daily.setSnow(snow); + + assertEquals(snow, daily.getSnow()); + } + + @Test + public void getEquals() { + final LocalDateTime now = LocalDateTime.now(); + final Daily first = new Daily(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final Daily second = new Daily(); + + assertEquals(first, second); + + first.setForecastTime(now); + + assertNotEquals(first, second); + + second.setForecastTime(now); + + assertEquals(first, second); + + first.setSunriseTime(now); + + assertNotEquals(first, second); + + second.setSunriseTime(now); + + assertEquals(first, second); + + first.setSunsetTime(now); + + assertNotEquals(first, second); + + second.setSunsetTime(now); + + assertEquals(first, second); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); + + final DailyTemperature dailyTemperature = new DailyTemperature(); + + first.setTemperature(dailyTemperature); + + assertNotEquals(first, second); + + second.setTemperature(dailyTemperature); + + assertEquals(first, second); + + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + + first.setAtmosphericPressure(atmosphericPressure); + + assertNotEquals(first, second); + + second.setAtmosphericPressure(atmosphericPressure); + + assertEquals(first, second); + + final Humidity humidity = Humidity.withValue((byte) 10); + + first.setHumidity(humidity); + + assertNotEquals(first, second); + + second.setHumidity(humidity); + + assertEquals(first, second); + + final Wind wind = Wind.withValue(13.2, "m/s"); + + first.setWind(wind); + + assertNotEquals(first, second); + + second.setWind(wind); + + assertEquals(first, second); + + final Clouds clouds = Clouds.withValue((byte) 25); + + first.setClouds(clouds); + + assertNotEquals(first, second); + + second.setClouds(clouds); + + assertEquals(first, second); + + final double uvIndex = 22.4; + + first.setUvIndex(uvIndex); + + assertNotEquals(first, second); + + second.setUvIndex(uvIndex); + + assertEquals(first, second); + + final double pop = 70.5; + + first.setProbabilityOfPrecipitation(pop); + + assertNotEquals(first, second); + + second.setProbabilityOfPrecipitation(pop); + + assertEquals(first, second); + + final DailyRain rain = DailyRain.withValue(20.2); + + first.setRain(rain); + + assertNotEquals(first, second); + + second.setRain(rain); + + assertEquals(first, second); + + final DailySnow snow = DailySnow.withValue(25.0); + + first.setSnow(snow); + + assertNotEquals(first, second); + + second.setSnow(snow); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final Daily first = new Daily(); + final Daily second = new Daily(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setForecastTime(LocalDateTime.now()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final LocalDateTime now = LocalDateTime.now(); + final Daily daily = new Daily(); + + daily.setForecastTime(now); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + daily.setWeatherState(weatherState); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final DailyTemperature dailyTemperature = new DailyTemperature(); + + daily.setTemperature(dailyTemperature); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + + daily.setAtmosphericPressure(atmosphericPressure); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final Wind wind = Wind.withValue(13.2, "m/s"); + + daily.setWind(wind); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final Clouds clouds = Clouds.withValue((byte) 25); + + daily.setClouds(clouds); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final DailyRain rain = DailyRain.withValue(20.2); + + daily.setRain(rain); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + + final DailySnow snow = DailySnow.withValue(25.0); + + daily.setSnow(snow); + + assertNotNull(daily.toString()); + assertNotEquals("", daily.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java new file mode 100644 index 0000000..15fa459 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/HourlyUnitTest.java @@ -0,0 +1,285 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class HourlyUnitTest { + @Test + public void getForecastTime() { + final Hourly hourly = new Hourly(); + final LocalDateTime now = LocalDateTime.now(); + hourly.setForecastTime(now); + + assertEquals(now, hourly.getForecastTime()); + } + + @Test + public void getWeatherState() { + final Hourly hourly = new Hourly(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + hourly.setWeatherState(weatherState); + + assertEquals(weatherState, hourly.getWeatherState()); + } + + @Test + public void getTemperature() { + final Hourly hourly = new Hourly(); + final Temperature temperature = Temperature.withValue(10, "K"); + hourly.setTemperature(temperature); + + assertEquals(temperature, hourly.getTemperature()); + } + + @Test + public void getAtmosphericPressure() { + final Hourly hourly = new Hourly(); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(100); + hourly.setAtmosphericPressure(atmosphericPressure); + + assertEquals(atmosphericPressure, hourly.getAtmosphericPressure()); + } + + @Test + public void getHumidity() { + final Hourly hourly = new Hourly(); + final Humidity humidity = Humidity.withValue((byte) 20); + hourly.setHumidity(humidity); + + assertEquals(humidity, hourly.getHumidity()); + } + + @Test + public void getUvIndex() { + final Hourly hourly = new Hourly(); + final double uvIndex = 20.0; + hourly.setUvIndex(uvIndex); + + assertEquals(uvIndex, hourly.getUvIndex(), 0.00001); + } + + @Test + public void getClouds() { + final Hourly hourly = new Hourly(); + final Clouds clouds = Clouds.withValue((byte) 60); + hourly.setClouds(clouds); + + assertEquals(clouds, hourly.getClouds()); + } + + @Test + public void getVisibilityInMetres() { + final Hourly hourly = new Hourly(); + final double vim = 40.0; + hourly.setVisibilityInMetres(vim); + + assertEquals(vim, hourly.getVisibilityInMetres(), 0.00001); + } + + @Test + public void getWind() { + final Hourly hourly = new Hourly(); + final Wind wind = Wind.withValue(200, "m/s"); + hourly.setWind(wind); + + assertEquals(wind, hourly.getWind()); + } + + @Test + public void getProbabilityOfPrecipitation() { + final Hourly hourly = new Hourly(); + final double pop = 42.0; + hourly.setProbabilityOfPrecipitation(pop); + + assertEquals(pop, hourly.getProbabilityOfPrecipitation(), 0.00001); + } + + @Test + public void getRain() { + final Hourly hourly = new Hourly(); + final Rain rain = Rain.withOneHourLevelValue(100); + hourly.setRain(rain); + + assertEquals(rain, hourly.getRain()); + } + + @Test + public void getSnow() { + final Hourly hourly = new Hourly(); + final Snow snow = Snow.withOneHourLevelValue(29); + hourly.setSnow(snow); + + assertEquals(snow, hourly.getSnow()); + } + + @Test + public void testEquals() { + final Hourly first = new Hourly(); + final Hourly second = new Hourly(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final LocalDateTime forecastTime = LocalDateTime.now(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + final Temperature temperature = Temperature.withValue(10, "K"); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(200); + final Humidity humidity = Humidity.withValue((byte) 13); + final double uvIndex = 10.0; + final Clouds clouds = Clouds.withValue((byte) 20); + final double vim = 20; + final Wind wind = Wind.withValue(20, "m/s"); + final double pop = 30; + final Rain rain = Rain.withOneHourLevelValue(40); + final Snow snow = Snow.withOneHourLevelValue(11); + + assertEquals(first, second); + + first.setForecastTime(forecastTime); + + assertNotEquals(first, second); + + second.setForecastTime(forecastTime); + + assertEquals(first, second); + + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); + + first.setTemperature(temperature); + + assertNotEquals(first, second); + + second.setTemperature(temperature); + + assertEquals(first, second); + + first.setAtmosphericPressure(atmosphericPressure); + + assertNotEquals(first, second); + + second.setAtmosphericPressure(atmosphericPressure); + + assertEquals(first, second); + + first.setHumidity(humidity); + + assertNotEquals(first, second); + + second.setHumidity(humidity); + + assertEquals(first, second); + + first.setUvIndex(uvIndex); + + assertNotEquals(first, second); + + second.setUvIndex(uvIndex); + + assertEquals(first, second); + + first.setClouds(clouds); + + assertNotEquals(first, second); + + second.setClouds(clouds); + + assertEquals(first, second); + + first.setVisibilityInMetres(vim); + + assertNotEquals(first, second); + + second.setVisibilityInMetres(vim); + + assertEquals(first, second); + + first.setWind(wind); + + assertNotEquals(first, second); + + second.setWind(wind); + + assertEquals(first, second); + + first.setProbabilityOfPrecipitation(pop); + + assertNotEquals(first, second); + + second.setProbabilityOfPrecipitation(pop); + + assertEquals(first, second); + + first.setRain(rain); + + assertNotEquals(first, second); + + second.setRain(rain); + + assertEquals(first, second); + + first.setSnow(snow); + + assertNotEquals(first, second); + + second.setSnow(snow); + + assertEquals(first, second); + } + + @Test + public void testHashCode() { + final Hourly first = new Hourly(); + final Hourly second = new Hourly(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setForecastTime(LocalDateTime.now()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Hourly hourly = new Hourly(); + hourly.setForecastTime(LocalDateTime.now()); + + assertNotNull(hourly.toString()); + assertNotEquals("", hourly.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/MinutelyUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/MinutelyUnitTest.java new file mode 100644 index 0000000..fb173ea --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/current/MinutelyUnitTest.java @@ -0,0 +1,86 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.current; + +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class MinutelyUnitTest { + @Test + public void withValue() { + final LocalDateTime now = LocalDateTime.now(); + final Minutely minutely = Minutely.withValue(now, 10.0); + + assertEquals(now, minutely.getForecastTime()); + assertEquals(10.0, minutely.getPrecipitationVolume(), 0.00001); + } + + @Test + public void withInvalidValueValue_negative() { + assertThrows(IllegalArgumentException.class, () -> Minutely.withValue(LocalDateTime.now(), -10.0)); + + } + + @Test + public void testEquals() { + final LocalDateTime now = LocalDateTime.now(); + final Minutely first = Minutely.withValue(now, 10.0); + final Minutely firstCopy = Minutely.withValue(now, 10.0); + final Minutely second = Minutely.withValue(now, 11.0); + final Minutely secondCopy = Minutely.withValue(now.plusMinutes(11), 11.0); + final Minutely third = Minutely.withValue(now.plusMinutes(22), 44.9); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + assertEquals(first, firstCopy); + assertNotEquals(first, second); + assertNotEquals(second, secondCopy); + assertNotEquals(second, third); + } + + @Test + public void testHashCode() { + final LocalDateTime now = LocalDateTime.now(); + final Minutely first = Minutely.withValue(now, 10.0); + final Minutely firstCopy = Minutely.withValue(now, 10.0); + final Minutely second = Minutely.withValue(now.plusMinutes(2), 11.0); + + assertEquals(first.hashCode(), first.hashCode()); + assertEquals(first.hashCode(), firstCopy.hashCode()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final Minutely minutely = Minutely.withValue(LocalDateTime.now(), 10.0); + + assertNotNull(minutely.toString()); + assertNotEquals("", minutely.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherDataUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherDataUnitTest.java new file mode 100644 index 0000000..42a28a9 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherDataUnitTest.java @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Coordinate; +import org.junit.jupiter.api.Test; + +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class HistoricalWeatherDataUnitTest { + @Test + public void getCoordinate() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + final Coordinate coordinate = Coordinate.of(11.2, 43.2); + historicalWeatherData.setCoordinate(coordinate); + + assertEquals(coordinate, historicalWeatherData.getCoordinate()); + } + + @Test + public void getTimezone() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + final ZoneId timeZone = ZoneId.of("GMT"); + historicalWeatherData.setTimezone(timeZone); + + assertEquals(timeZone, historicalWeatherData.getTimezone()); + } + + @Test + public void getTimezoneOffset() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + final ZoneOffset offset = ZoneOffset.UTC; + historicalWeatherData.setTimezoneOffset(offset); + + assertEquals(offset, historicalWeatherData.getTimezoneOffset()); + } + + @Test + public void getHistoricalWeather() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + final HistoricalWeather historicalWeather = new HistoricalWeather(); + historicalWeatherData.setHistoricalWeather(historicalWeather); + + assertEquals(historicalWeather, historicalWeatherData.getHistoricalWeather()); + } + + @Test + public void getHourlyList() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + final List hourlyList = new ArrayList<>(); + historicalWeatherData.setHourlyList(hourlyList); + + assertEquals(hourlyList, historicalWeatherData.getHourlyList()); + } + + @Test + public void getEquals() { + final HistoricalWeatherData first = new HistoricalWeatherData(); + final HistoricalWeatherData second = new HistoricalWeatherData(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final Coordinate coordinate = Coordinate.of(11, 12); + final ZoneId timeZone = ZoneId.of("GMT"); + final ZoneOffset offset = ZoneOffset.UTC; + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final List hourlyList = new ArrayList<>(); + + assertEquals(first, second); + + first.setCoordinate(coordinate); + + assertNotEquals(first, second); + + second.setCoordinate(coordinate); + + assertEquals(first, second); + + first.setTimezone(timeZone); + + assertNotEquals(first, second); + + second.setTimezone(timeZone); + + assertEquals(first, second); + + first.setTimezoneOffset(offset); + + assertNotEquals(first, second); + + second.setTimezoneOffset(offset); + + assertEquals(first, second); + + first.setHistoricalWeather(historicalWeather); + + assertNotEquals(first, second); + + second.setHistoricalWeather(historicalWeather); + + assertEquals(first, second); + + first.setHourlyList(hourlyList); + + assertNotEquals(first, second); + + second.setHourlyList(hourlyList); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final HistoricalWeatherData first = new HistoricalWeatherData(); + final HistoricalWeatherData second = new HistoricalWeatherData(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setCoordinate(Coordinate.of(11, 42)); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final HistoricalWeatherData historicalWeatherData = new HistoricalWeatherData(); + historicalWeatherData.setCoordinate(Coordinate.of(32, 22)); + + assertNotNull(historicalWeatherData.toString()); + assertNotEquals("", historicalWeatherData.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java new file mode 100644 index 0000000..620747e --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HistoricalWeatherUnitTest.java @@ -0,0 +1,336 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class HistoricalWeatherUnitTest { + @Test + public void getForecastTime() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final LocalDateTime now = LocalDateTime.now(); + historicalWeather.setForecastTime(now); + + assertEquals(now, historicalWeather.getForecastTime()); + } + + @Test + public void getSunriseTime() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final LocalDateTime now = LocalDateTime.now(); + historicalWeather.setSunriseTime(now); + + assertEquals(now, historicalWeather.getSunriseTime()); + } + + @Test + public void getSunsetTime() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final LocalDateTime now = LocalDateTime.now(); + historicalWeather.setSunsetTime(now); + + assertEquals(now, historicalWeather.getSunsetTime()); + } + + @Test + public void getWeatherState() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + historicalWeather.setWeatherState(weatherState); + + assertEquals(weatherState, historicalWeather.getWeatherState()); + } + + @Test + public void getTemperature() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Temperature temperature = Temperature.withValue(10, "K"); + + historicalWeather.setTemperature(temperature); + + assertEquals(temperature, historicalWeather.getTemperature()); + } + + @Test + public void getAtmosphericPressure() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + historicalWeather.setAtmosphericPressure(atmosphericPressure); + + assertEquals(atmosphericPressure, historicalWeather.getAtmosphericPressure()); + } + + @Test + public void getHumidity() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Humidity humidity = Humidity.withValue((byte) 10); + historicalWeather.setHumidity(humidity); + + assertEquals(humidity, historicalWeather.getHumidity()); + } + + @Test + public void getWind() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Wind wind = Wind.withValue(13.2, "m/s"); + historicalWeather.setWind(wind); + + assertEquals(wind, historicalWeather.getWind()); + } + + @Test + public void getClouds() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Clouds clouds = Clouds.withValue((byte) 25); + historicalWeather.setClouds(clouds); + + assertEquals(clouds, historicalWeather.getClouds()); + } + + @Test + public void getUvIndex() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final double uvIndex = 22.4; + historicalWeather.setUvIndex(uvIndex); + + assertEquals(uvIndex, historicalWeather.getUvIndex(), 0.00001); + + historicalWeather.setUvIndex(null); + + assertNull(historicalWeather.getUvIndex()); + } + + @Test + public void getIllegalUvIndexValue() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + + assertThrows(IllegalArgumentException.class, () -> historicalWeather.setUvIndex(-1.2)); + } + + @Test + public void getProbabilityOfPrecipitation() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final double vim = 120; + historicalWeather.setVisibilityInMetres(vim); + + assertEquals(vim, historicalWeather.getVisibilityInMetres(), 0.00001); + + historicalWeather.setVisibilityInMetres(null); + + assertNull(historicalWeather.getVisibilityInMetres()); + } + + @Test + public void getIllegalProbabilityOfPrecipitationValue_negative() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + + assertThrows(IllegalArgumentException.class, () -> historicalWeather.setVisibilityInMetres(-20.0)); + } + + @Test + public void getRain() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Rain rain = Rain.withOneHourLevelValue(20.2); + historicalWeather.setRain(rain); + + assertEquals(rain, historicalWeather.getRain()); + } + + @Test + public void getSnow() { + final HistoricalWeather historicalWeather = new HistoricalWeather(); + final Snow snow = Snow.withOneHourLevelValue(25.0); + historicalWeather.setSnow(snow); + + assertEquals(snow, historicalWeather.getSnow()); + } + + @Test + public void getEquals() { + final LocalDateTime now = LocalDateTime.now(); + final HistoricalWeather first = new HistoricalWeather(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final HistoricalWeather second = new HistoricalWeather(); + + assertEquals(first, second); + + first.setForecastTime(now); + + assertNotEquals(first, second); + + second.setForecastTime(now); + + assertEquals(first, second); + + first.setSunriseTime(now); + + assertNotEquals(first, second); + + second.setSunriseTime(now); + + assertEquals(first, second); + + first.setSunsetTime(now); + + assertNotEquals(first, second); + + second.setSunsetTime(now); + + assertEquals(first, second); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); + + final Temperature temperature = Temperature.withValue(10, "K"); + + first.setTemperature(temperature); + + assertNotEquals(first, second); + + second.setTemperature(temperature); + + assertEquals(first, second); + + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(22.3); + + first.setAtmosphericPressure(atmosphericPressure); + + assertNotEquals(first, second); + + second.setAtmosphericPressure(atmosphericPressure); + + assertEquals(first, second); + + final Humidity humidity = Humidity.withValue((byte) 10); + + first.setHumidity(humidity); + + assertNotEquals(first, second); + + second.setHumidity(humidity); + + assertEquals(first, second); + + final Wind wind = Wind.withValue(13.2, "m/s"); + + first.setWind(wind); + + assertNotEquals(first, second); + + second.setWind(wind); + + assertEquals(first, second); + + final Clouds clouds = Clouds.withValue((byte) 25); + + first.setClouds(clouds); + + assertNotEquals(first, second); + + second.setClouds(clouds); + + assertEquals(first, second); + + final double uvIndex = 22.4; + + first.setUvIndex(uvIndex); + + assertNotEquals(first, second); + + second.setUvIndex(uvIndex); + + assertEquals(first, second); + + final double vim = 250; + + first.setVisibilityInMetres(vim); + + assertNotEquals(first, second); + + second.setVisibilityInMetres(vim); + + assertEquals(first, second); + + final Rain rain = Rain.withOneHourLevelValue(20.2); + + first.setRain(rain); + + assertNotEquals(first, second); + + second.setRain(rain); + + assertEquals(first, second); + + final Snow snow = Snow.withOneHourLevelValue(25.0); + + first.setSnow(snow); + + assertNotEquals(first, second); + + second.setSnow(snow); + + assertEquals(first, second); + } + + @Test + public void getHashCode() { + final HistoricalWeather first = new HistoricalWeather(); + final HistoricalWeather second = new HistoricalWeather(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setForecastTime(LocalDateTime.now()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void getToString() { + final LocalDateTime now = LocalDateTime.now(); + final HistoricalWeather historicalWeather = new HistoricalWeather(); + + historicalWeather.setForecastTime(now); + + assertNotNull(historicalWeather.toString()); + assertNotEquals("", historicalWeather.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java new file mode 100644 index 0000000..0b04fa3 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/model/onecall/historical/HourlyHistoricalUnitTest.java @@ -0,0 +1,249 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.model.onecall.historical; + +import com.github.prominence.openweathermap.api.model.Clouds; +import com.github.prominence.openweathermap.api.model.Humidity; +import com.github.prominence.openweathermap.api.model.WeatherState; +import com.github.prominence.openweathermap.api.model.onecall.*; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; + +import static org.junit.jupiter.api.Assertions.*; + +public class HourlyHistoricalUnitTest { + @Test + public void getForecastTime() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final LocalDateTime now = LocalDateTime.now(); + hourlyHistorical.setForecastTime(now); + + assertEquals(now, hourlyHistorical.getForecastTime()); + } + + @Test + public void getWeatherState() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + hourlyHistorical.setWeatherState(weatherState); + + assertEquals(weatherState, hourlyHistorical.getWeatherState()); + } + + @Test + public void getTemperature() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Temperature temperature = Temperature.withValue(10, "K"); + hourlyHistorical.setTemperature(temperature); + + assertEquals(temperature, hourlyHistorical.getTemperature()); + } + + @Test + public void getAtmosphericPressure() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(100); + hourlyHistorical.setAtmosphericPressure(atmosphericPressure); + + assertEquals(atmosphericPressure, hourlyHistorical.getAtmosphericPressure()); + } + + @Test + public void getHumidity() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Humidity humidity = Humidity.withValue((byte) 20); + hourlyHistorical.setHumidity(humidity); + + assertEquals(humidity, hourlyHistorical.getHumidity()); + } + + @Test + public void getClouds() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Clouds clouds = Clouds.withValue((byte) 60); + hourlyHistorical.setClouds(clouds); + + assertEquals(clouds, hourlyHistorical.getClouds()); + } + + @Test + public void getVisibilityInMetres() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final double vim = 40.0; + hourlyHistorical.setVisibilityInMetres(vim); + + assertEquals(vim, hourlyHistorical.getVisibilityInMetres(), 0.00001); + } + + @Test + public void getWind() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Wind wind = Wind.withValue(200, "m/s"); + hourlyHistorical.setWind(wind); + + assertEquals(wind, hourlyHistorical.getWind()); + } + + @Test + public void getRain() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Rain rain = Rain.withOneHourLevelValue(100); + hourlyHistorical.setRain(rain); + + assertEquals(rain, hourlyHistorical.getRain()); + } + + @Test + public void getSnow() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + final Snow snow = Snow.withOneHourLevelValue(29); + hourlyHistorical.setSnow(snow); + + assertEquals(snow, hourlyHistorical.getSnow()); + } + + @Test + public void testEquals() { + final HourlyHistorical first = new HourlyHistorical(); + final HourlyHistorical second = new HourlyHistorical(); + + assertEquals(first, first); + assertNotEquals(first, null); + assertNotEquals(first, new Object()); + + final LocalDateTime forecastTime = LocalDateTime.now(); + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + final Temperature temperature = Temperature.withValue(10, "K"); + final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(200); + final Humidity humidity = Humidity.withValue((byte) 13); + final Clouds clouds = Clouds.withValue((byte) 20); + final double vim = 20; + final Wind wind = Wind.withValue(20, "m/s"); + final Rain rain = Rain.withOneHourLevelValue(40); + final Snow snow = Snow.withOneHourLevelValue(11); + + assertEquals(first, second); + + first.setForecastTime(forecastTime); + + assertNotEquals(first, second); + + second.setForecastTime(forecastTime); + + assertEquals(first, second); + + first.setWeatherState(weatherState); + + assertNotEquals(first, second); + + second.setWeatherState(weatherState); + + assertEquals(first, second); + + first.setTemperature(temperature); + + assertNotEquals(first, second); + + second.setTemperature(temperature); + + assertEquals(first, second); + + first.setAtmosphericPressure(atmosphericPressure); + + assertNotEquals(first, second); + + second.setAtmosphericPressure(atmosphericPressure); + + assertEquals(first, second); + + first.setHumidity(humidity); + + assertNotEquals(first, second); + + second.setHumidity(humidity); + + assertEquals(first, second); + + first.setClouds(clouds); + + assertNotEquals(first, second); + + second.setClouds(clouds); + + assertEquals(first, second); + + first.setVisibilityInMetres(vim); + + assertNotEquals(first, second); + + second.setVisibilityInMetres(vim); + + assertEquals(first, second); + + first.setWind(wind); + + assertNotEquals(first, second); + + second.setWind(wind); + + assertEquals(first, second); + + first.setRain(rain); + + assertNotEquals(first, second); + + second.setRain(rain); + + assertEquals(first, second); + + first.setSnow(snow); + + assertNotEquals(first, second); + + second.setSnow(snow); + + assertEquals(first, second); + } + + @Test + public void testHashCode() { + final HourlyHistorical first = new HourlyHistorical(); + final HourlyHistorical second = new HourlyHistorical(); + + assertEquals(first.hashCode(), second.hashCode()); + + first.setForecastTime(LocalDateTime.now()); + + assertNotEquals(first.hashCode(), second.hashCode()); + } + + @Test + public void testToString() { + final HourlyHistorical hourlyHistorical = new HourlyHistorical(); + hourlyHistorical.setForecastTime(LocalDateTime.now()); + + assertNotNull(hourlyHistorical.toString()); + assertNotEquals("", hourlyHistorical.toString()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/LocationUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/LocationUnitTest.java index 9f0e505..dfcd359 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/LocationUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/LocationUnitTest.java @@ -23,21 +23,22 @@ package com.github.prominence.openweathermap.api.model.weather; import com.github.prominence.openweathermap.api.model.Coordinate; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; import java.time.ZoneOffset; +import static org.junit.jupiter.api.Assertions.*; + public class LocationUnitTest { @Test public void whenCreateObjectWithValidArgs_thenObjectIsCreated() { Location.withValues(33, "test"); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateObjectWithoutName_thenThrowAnException() { - Location.withValues(33, null); + assertThrows(IllegalArgumentException.class, () -> Location.withValues(33, null)); } @Test @@ -45,7 +46,7 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setId(55); - Assert.assertEquals(55, location.getId()); + assertEquals(55, location.getId()); } @Test @@ -53,7 +54,7 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setName("city"); - Assert.assertEquals("city", location.getName()); + assertEquals("city", location.getName()); } @Test @@ -61,25 +62,25 @@ public class LocationUnitTest { final Location location = Location.withValues(33, "test"); location.setCountryCode("by"); - Assert.assertEquals("by", location.getCountryCode()); + assertEquals("by", location.getCountryCode()); } @Test public void whenSetSunrise_thenValueIsSet() { final Location location = Location.withValues(33, "test"); final LocalDateTime now = LocalDateTime.now(); - location.setSunrise(now); + location.setSunriseTime(now); - Assert.assertEquals(now, location.getSunrise()); + assertEquals(now, location.getSunriseTime()); } @Test public void whenSetSunset_thenValueIsSet() { final Location location = Location.withValues(33, "test"); final LocalDateTime now = LocalDateTime.now(); - location.setSunset(now); + location.setSunsetTime(now); - Assert.assertEquals(now, location.getSunset()); + assertEquals(now, location.getSunsetTime()); } @Test @@ -88,32 +89,32 @@ public class LocationUnitTest { final ZoneOffset offset = ZoneOffset.UTC; location.setZoneOffset(offset); - Assert.assertEquals(offset, location.getZoneOffset()); + assertEquals(offset, location.getZoneOffset()); } @Test public void whenSetCoordinate_thenValueIsSet() { final Location location = Location.withValues(33, "test"); - final Coordinate coordinate = Coordinate.withValues(33.2, 64.2); + final Coordinate coordinate = Coordinate.of(33.2, 64.2); location.setCoordinate(coordinate); - Assert.assertEquals(coordinate, location.getCoordinate()); + assertEquals(coordinate, location.getCoordinate()); } @Test public void whenCallToString_thenAllIsFine() { final Location location = Location.withValues(44, "test"); - Assert.assertNotEquals("", location.toString()); + assertNotEquals("", location.toString()); - location.setCoordinate(Coordinate.withValues(33.2, 56.3)); + location.setCoordinate(Coordinate.of(33.2, 56.3)); - Assert.assertNotEquals("", location.toString()); + assertNotEquals("", location.toString()); location.setCountryCode("TN"); - Assert.assertNotEquals("", location.toString()); - Assert.assertNotNull(location.toString()); + assertNotEquals("", location.toString()); + assertNotNull(location.toString()); } @Test @@ -121,11 +122,11 @@ public class LocationUnitTest { final Location one = Location.withValues(44, "test"); final Location two = Location.withValues(44, "test"); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one.hashCode(), two.hashCode()); two.setName("112"); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test @@ -133,69 +134,69 @@ public class LocationUnitTest { final Location one = Location.withValues(44, "test"); final Location two = Location.withValues(44, "test"); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(new Object())); + assertEquals(one, one); + assertNotEquals(one, new Object()); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); two.setId(23); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); one.setId(23); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setName("23"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setName("23"); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setCountryCode("11"); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setCountryCode("11"); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final LocalDateTime now = LocalDateTime.now(); - one.setSunrise(now); + one.setSunriseTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); - two.setSunrise(now); + two.setSunriseTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); - one.setSunset(now); + one.setSunsetTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); - two.setSunset(now); + two.setSunsetTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); one.setZoneOffset(ZoneOffset.UTC); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setZoneOffset(ZoneOffset.UTC); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); - final Coordinate coordinate = Coordinate.withValues(33.5, -22.4); + final Coordinate coordinate = Coordinate.of(33.5, -22.4); one.setCoordinate(coordinate); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setCoordinate(coordinate); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/RainUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/RainUnitTest.java index accfa50..f27c538 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/RainUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/RainUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model.weather; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class RainUnitTest { @Test @@ -37,36 +38,43 @@ public class RainUnitTest { public void whenSetValues_thenTheyAreSet() { final Rain rain = Rain.withValues(0, 0); - rain.setOneHourRainLevel(33.3); - Assert.assertEquals(33.3, rain.getOneHourRainLevel(), 0.00001); + rain.setOneHourLevel(33.3); + assertEquals(33.3, rain.getOneHourLevel(), 0.00001); - rain.setThreeHourRainLevel(55.5); - Assert.assertEquals(55.5, rain.getThreeHourRainLevel(), 0.00001); + rain.setThreeHourLevel(55.5); + assertEquals(55.5, rain.getThreeHourLevel(), 0.00001); } @Test public void whenCallToString_thenAllIsFine() { Rain rain = Rain.withThreeHourLevelValue(33.5); - Assert.assertNotNull(rain.toString()); - Assert.assertNotEquals("", rain.toString()); + assertNotNull(rain.toString()); + assertNotEquals("", rain.toString()); - rain.setOneHourRainLevel(22.2); + rain.setOneHourLevel(22.2); - Assert.assertNotNull(rain.toString()); - Assert.assertNotEquals("", rain.toString()); + assertNotNull(rain.toString()); + assertNotEquals("", rain.toString()); + + rain = Rain.withOneHourLevelValue(22.4); + + assertNotNull(rain.toString()); + assertNotEquals("", rain.toString()); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidOneHourLevelValue_thenFail() { final Rain rain = Rain.withValues(0, 0); - rain.setOneHourRainLevel(-20); + + assertThrows(IllegalArgumentException.class, () -> rain.setOneHourLevel(-20)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidThreeHourLevelValue_thenFail() { final Rain rain = Rain.withValues(0, 0); - rain.setThreeHourRainLevel(-20); + + assertThrows(IllegalArgumentException.class, () -> rain.setThreeHourLevel(-20)); } @Test @@ -74,23 +82,23 @@ public class RainUnitTest { final Rain first = Rain.withValues(0, 0); final Rain second = Rain.withValues(0, 0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - second.setThreeHourRainLevel(11.0); + second.setThreeHourLevel(11.0); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - first.setThreeHourRainLevel(11.0); + first.setThreeHourLevel(11.0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - first.setOneHourRainLevel(333.2); + first.setOneHourLevel(333.2); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - second.setOneHourRainLevel(333.2); + second.setOneHourLevel(333.2); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test @@ -98,24 +106,24 @@ public class RainUnitTest { final Rain first = Rain.withValues(0, 0); final Rain second = Rain.withValues(0, 0); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); - first.setOneHourRainLevel(0.34); + first.setOneHourLevel(0.34); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - second.setOneHourRainLevel(0.34); + second.setOneHourLevel(0.34); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); - second.setThreeHourRainLevel(66.7); + second.setThreeHourLevel(66.7); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - first.setThreeHourRainLevel(66.7); + first.setThreeHourLevel(66.7); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/SnowUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/SnowUnitTest.java index d0b4c92..a4cf3fd 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/SnowUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/SnowUnitTest.java @@ -22,8 +22,9 @@ package com.github.prominence.openweathermap.api.model.weather; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class SnowUnitTest { @Test @@ -37,41 +38,46 @@ public class SnowUnitTest { public void whenSetValues_thenTheyAreSet() { final Snow snow = Snow.withValues(0, 0); - snow.setOneHourSnowLevel(33.3); - Assert.assertEquals(33.3, snow.getOneHourSnowLevel(), 0.00001); + snow.setOneHourLevel(33.3); + assertEquals(33.3, snow.getOneHourLevel(), 0.00001); - snow.setThreeHourSnowLevel(55.5); - Assert.assertEquals(55.5, snow.getThreeHourSnowLevel(), 0.00001); + snow.setThreeHourLevel(55.5); + assertEquals(55.5, snow.getThreeHourLevel(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidOneHourLevelValue_thenFail() { final Snow rain = Snow.withValues(0, 0); - rain.setOneHourSnowLevel(-20); + assertThrows(IllegalArgumentException.class, () -> rain.setOneHourLevel(-20)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidThreeHourLevelValue_thenFail() { final Snow rain = Snow.withValues(0, 0); - rain.setThreeHourSnowLevel(-20); + assertThrows(IllegalArgumentException.class, () -> rain.setThreeHourLevel(-20)); } @Test public void whenCallToString_thenAllIsFine() { - final Snow snow = Snow.withOneHourLevelValue(33.5); + Snow snow = Snow.withOneHourLevelValue(33.5); - Assert.assertNotNull(snow.toString()); - Assert.assertNotEquals("", snow.toString()); + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); - snow.setOneHourSnowLevel(22.2); + snow.setOneHourLevel(22.2); - Assert.assertNotNull(snow.toString()); - Assert.assertNotEquals("", snow.toString()); + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); - snow.setThreeHourSnowLevel(33.2); + snow.setThreeHourLevel(33.2); - Assert.assertNotNull(snow.toString()); - Assert.assertNotEquals("", snow.toString()); + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); + + snow = Snow.withThreeHourLevelValue(33.2); + + assertNotNull(snow.toString()); + assertNotEquals("", snow.toString()); } @Test @@ -79,23 +85,23 @@ public class SnowUnitTest { final Snow first = Snow.withValues(0, 0); final Snow second = Snow.withValues(0, 0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - second.setThreeHourSnowLevel(11.0); + second.setThreeHourLevel(11.0); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - first.setThreeHourSnowLevel(11.0); + first.setThreeHourLevel(11.0); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); - first.setOneHourSnowLevel(333.2); + first.setOneHourLevel(333.2); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); - second.setOneHourSnowLevel(333.2); + second.setOneHourLevel(333.2); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test @@ -103,24 +109,24 @@ public class SnowUnitTest { final Snow first = Snow.withValues(0, 0); final Snow second = Snow.withValues(0, 0); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); - first.setOneHourSnowLevel(0.34); + first.setOneHourLevel(0.34); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - second.setOneHourSnowLevel(0.34); + second.setOneHourLevel(0.34); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); - second.setThreeHourSnowLevel(66.7); + second.setThreeHourLevel(66.7); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); - first.setThreeHourSnowLevel(66.7); + first.setThreeHourLevel(66.7); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java index 47547cf..b92e446 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WeatherUnitTest.java @@ -22,155 +22,98 @@ package com.github.prominence.openweathermap.api.model.weather; -import com.github.prominence.openweathermap.api.model.AtmosphericPressure; -import com.github.prominence.openweathermap.api.model.Clouds; -import com.github.prominence.openweathermap.api.model.Humidity; -import com.github.prominence.openweathermap.api.model.Temperature; -import org.junit.Assert; -import org.junit.Test; +import com.github.prominence.openweathermap.api.model.*; +import org.junit.jupiter.api.Test; import java.time.LocalDateTime; +import static org.junit.jupiter.api.Assertions.*; + public class WeatherUnitTest { - @Test - public void whenCreateObjectWithValidArgs_thenObjectIsCreated() { - Weather.forValue("state", "desc"); - } - - @Test(expected = IllegalArgumentException.class) - public void whenCreateObjectWithoutState_thenThrowAnException() { - Weather.forValue(null, "desc"); - } - - @Test(expected = IllegalArgumentException.class) - public void whenCreateObjectWithoutDescription_thenThrowAnException() { - Weather.forValue("state", null); - } - - @Test - public void whenSetState_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); - weather.setState("test"); - - Assert.assertEquals("test", weather.getState()); - } - - @Test(expected = IllegalArgumentException.class) - public void whenSetNullState_thenThrowAnException() { - final Weather weather = Weather.forValue("state", "desc"); - weather.setState(null); - } - - @Test - public void whenSetDescription_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); - weather.setDescription("test"); - - Assert.assertEquals("test", weather.getDescription()); - } - - @Test(expected = IllegalArgumentException.class) - public void whenSetNullDescription_thenThrowAnException() { - final Weather weather = Weather.forValue("state", "desc"); - weather.setDescription(null); - } - - @Test - public void whenSetIconId_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); - Assert.assertNull(weather.getWeatherIconId()); - Assert.assertNull(weather.getWeatherIconUrl()); - - weather.setWeatherIconId("11d"); - - Assert.assertEquals("11d", weather.getWeatherIconId()); - Assert.assertNotNull(weather.getWeatherIconUrl()); - } - @Test public void whenSetRequestedOn_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final LocalDateTime now = LocalDateTime.now(); - weather.setCalculatedOn(now); + weather.setCalculationTime(now); - Assert.assertEquals(now, weather.getCalculatedOn()); + assertEquals(now, weather.getCalculationTime()); } @Test public void whenSetTemperature_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Temperature temperature = Temperature.withValue(22.3, "a"); weather.setTemperature(temperature); - Assert.assertEquals(temperature, weather.getTemperature()); + assertEquals(temperature, weather.getTemperature()); } @Test public void whenSetPressure_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(33.2); weather.setAtmosphericPressure(atmosphericPressure); - Assert.assertEquals(atmosphericPressure, weather.getAtmosphericPressure()); + assertEquals(atmosphericPressure, weather.getAtmosphericPressure()); } @Test public void whenSetHumidity_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Humidity humidity = Humidity.withValue((byte) 44); weather.setHumidity(humidity); - Assert.assertEquals(humidity, weather.getHumidity()); + assertEquals(humidity, weather.getHumidity()); } @Test public void whenSetWind_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Wind wind = Wind.withValue(22.2, "a"); weather.setWind(wind); - Assert.assertEquals(wind, weather.getWind()); + assertEquals(wind, weather.getWind()); } @Test public void whenSetRain_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Rain rain = Rain.withValues(0, 0); weather.setRain(rain); - Assert.assertEquals(rain, weather.getRain()); + assertEquals(rain, weather.getRain()); } @Test public void whenSetSnow_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Snow snow = Snow.withValues(0, 0); weather.setSnow(snow); - Assert.assertEquals(snow, weather.getSnow()); + assertEquals(snow, weather.getSnow()); } @Test public void whenSetClouds_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Clouds clouds = Clouds.withValue((byte) 33); weather.setClouds(clouds); - Assert.assertEquals(clouds, weather.getClouds()); + assertEquals(clouds, weather.getClouds()); } @Test public void whenSetLocation_thenValueIsSet() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Location location = Location.withValues(22, "asd"); weather.setLocation(location); - Assert.assertEquals(location, weather.getLocation()); + assertEquals(location, weather.getLocation()); } @Test public void whenCallToString_thenAllIsFine() { - final Weather weather = Weather.forValue("state", "desc"); + final Weather weather = new Weather(); final Location location = Location.withValues(12312, "asd"); final Temperature temperature = Temperature.withValue(33.2, "asd"); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(44.4); @@ -178,154 +121,155 @@ public class WeatherUnitTest { final Rain rain = Rain.withOneHourLevelValue(33.2); final Snow snow = Snow.withOneHourLevelValue(33.1); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setLocation(location); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); location.setCountryCode("3d"); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setTemperature(temperature); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setAtmosphericPressure(atmosphericPressure); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setClouds(clouds); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setRain(rain); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); + + weather.setRain(Rain.withThreeHourLevelValue(33)); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); weather.setSnow(snow); - Assert.assertNotEquals("", weather.toString()); - Assert.assertNotNull(weather.toString()); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); + + weather.setSnow(Snow.withThreeHourLevelValue(44)); + assertNotEquals("", weather.toString()); + assertNotNull(weather.toString()); } @Test public void whenCallHashCode_thenAllIsFine() { - final Weather one = Weather.forValue("state", "desc"); - final Weather two = Weather.forValue("state", "desc"); + final Weather one = new Weather(); + final Weather two = new Weather(); - Assert.assertEquals(one.hashCode(), two.hashCode()); + assertEquals(one.hashCode(), two.hashCode()); - two.setDescription("112"); + two.setCalculationTime(LocalDateTime.now()); - Assert.assertNotEquals(one.hashCode(), two.hashCode()); + assertNotEquals(one.hashCode(), two.hashCode()); } @Test public void whenCheckEquality_thenAllIsFine() { - final Weather one = Weather.forValue("state", "desc"); - final Weather two = Weather.forValue("state1", "desc1"); + final Weather one = new Weather(); + final Weather two = new Weather(); - Assert.assertTrue(one.equals(one)); - Assert.assertFalse(one.equals(new Object())); - Assert.assertFalse(one.equals(two)); - - two.setState("state"); - - Assert.assertFalse(one.equals(two)); - - two.setDescription("desc"); - - Assert.assertTrue(one.equals(two)); - - one.setWeatherIconId("1"); - - Assert.assertFalse(one.equals(two)); - - two.setWeatherIconId("1"); - - Assert.assertTrue(one.equals(two)); + assertEquals(one, one); + assertNotEquals(one, new Object()); + assertEquals(one, two); final LocalDateTime now = LocalDateTime.now(); - one.setCalculatedOn(now); + one.setCalculationTime(now); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); - two.setCalculatedOn(now); + two.setCalculationTime(now); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Temperature temperature = Temperature.withValue(33.2, "as"); one.setTemperature(temperature); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setTemperature(temperature); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); + + final WeatherState weatherState = new WeatherState(800, "Clear", "clear sky"); + one.setWeatherState(weatherState); + + assertNotEquals(one, two); + + two.setWeatherState(weatherState); + + assertEquals(one, two); final AtmosphericPressure atmosphericPressure = AtmosphericPressure.withValue(33.33); one.setAtmosphericPressure(atmosphericPressure); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setAtmosphericPressure(atmosphericPressure); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Humidity humidity = Humidity.withValue((byte) 33); one.setHumidity(humidity); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setHumidity(humidity); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Wind wind = Wind.withValue(33.6, "asd"); one.setWind(wind); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setWind(wind); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Rain rain = Rain.withValues(0, 0); one.setRain(rain); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setRain(rain); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Snow snow = Snow.withValues(0, 0); one.setSnow(snow); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setSnow(snow); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Clouds clouds = Clouds.withValue((byte) 33); one.setClouds(clouds); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setClouds(clouds); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); final Location location = Location.withValues(231, "asda"); one.setLocation(location); - Assert.assertFalse(one.equals(two)); + assertNotEquals(one, two); two.setLocation(location); - Assert.assertTrue(one.equals(two)); + assertEquals(one, two); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WindUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WindUnitTest.java index 3f57404..2da62a5 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/model/weather/WindUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/model/weather/WindUnitTest.java @@ -22,103 +22,106 @@ package com.github.prominence.openweathermap.api.model.weather; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; public class WindUnitTest { @Test public void whenCreateWindWithValidArgs_thenValueIsSet() { - Assert.assertEquals(44.0, Wind.withValue(44, "ms").getSpeed(), 0.00001); + assertEquals(44.0, Wind.withValue(44, "ms").getSpeed(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWindWithInvalidSpeedArg_thenThrowAnException() { - Wind.withValue(-21, "a"); + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(-21, "a")); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenCreateWindWithInvalidUnitArg_thenThrowAnException() { - Wind.withValue(342, null); + assertThrows(IllegalArgumentException.class, () -> Wind.withValue(342, null)); } @Test public void whenSetValidSpeed_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(33, wind.getSpeed(), 0.00001); + assertEquals(33, wind.getSpeed(), 0.00001); wind.setSpeed(0); - Assert.assertEquals(0, wind.getSpeed(), 0.00001); + assertEquals(0, wind.getSpeed(), 0.00001); wind.setSpeed(3656); - Assert.assertEquals(3656, wind.getSpeed(), 0.00001); + assertEquals(3656, wind.getSpeed(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidSpeedBelow0_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(33, wind.getSpeed(), 0.00001); + assertEquals(33, wind.getSpeed(), 0.00001); - wind.setSpeed(-22); + assertThrows(IllegalArgumentException.class, () -> wind.setSpeed(-22)); } @Test public void whenSetValidDegrees_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertNull(wind.getDegrees()); + assertNull(wind.getDegrees()); wind.setDegrees(22); - Assert.assertEquals(22, wind.getDegrees(), 0.00001); + assertEquals(22, wind.getDegrees(), 0.00001); wind.setDegrees(0); - Assert.assertEquals(0, wind.getDegrees(), 0.00001); + assertEquals(0, wind.getDegrees(), 0.00001); wind.setDegrees(360); - Assert.assertEquals(360, wind.getDegrees(), 0.00001); + assertEquals(360, wind.getDegrees(), 0.00001); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidDegreesBelow0_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setDegrees(-32); + + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(-32)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidDegreesAbove360_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setDegrees(378); + + assertThrows(IllegalArgumentException.class, () -> wind.setDegrees(378)); } @Test public void whenSetNonNullUnit_thenValueIsSet() { final Wind wind = Wind.withValue(33, "as"); - Assert.assertEquals(wind.getUnit(), "as"); + assertEquals(wind.getUnit(), "as"); wind.setUnit("myUnit"); - Assert.assertEquals(wind.getUnit(), "myUnit"); + assertEquals(wind.getUnit(), "myUnit"); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetNullUnit_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setUnit(null); + assertThrows(IllegalArgumentException.class, () -> wind.setUnit(null)); } - @Test(expected = IllegalArgumentException.class) + @Test public void whenSetInvalidGustValue_thenThrowAnException() { final Wind wind = Wind.withValue(33, "as"); - wind.setGust(-50); + assertThrows(IllegalArgumentException.class, () -> wind.setGust(-50)); } @Test @@ -127,23 +130,23 @@ public class WindUnitTest { wind.setGust(30); - Assert.assertEquals(30, wind.getGust(), 0.00001); + assertEquals(30, wind.getGust(), 0.00001); } @Test public void whenCallToString_thenAllIsFine() { final Wind wind = Wind.withValue(302, "a"); - Assert.assertNotNull(wind.toString()); + assertNotNull(wind.toString()); wind.setDegrees(22); - Assert.assertNotNull(wind.toString()); - Assert.assertNotEquals("", wind.toString()); + assertNotNull(wind.toString()); + assertNotEquals("", wind.toString()); wind.setGust(20); - Assert.assertNotNull(wind.toString()); - Assert.assertNotEquals("", wind.toString()); + assertNotNull(wind.toString()); + assertNotEquals("", wind.toString()); } @Test @@ -151,23 +154,23 @@ public class WindUnitTest { final Wind first = Wind.withValue(22, "a"); final Wind second = Wind.withValue(22, "b"); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); second.setUnit("a"); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); second.setSpeed(33); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); first.setSpeed(333); - Assert.assertNotEquals(first.hashCode(), second.hashCode()); + assertNotEquals(first.hashCode(), second.hashCode()); first.setSpeed(33); - Assert.assertEquals(first.hashCode(), second.hashCode()); + assertEquals(first.hashCode(), second.hashCode()); } @Test @@ -175,32 +178,36 @@ public class WindUnitTest { final Wind first = Wind.withValue(11, "a"); final Wind second = Wind.withValue(11, "a"); - Assert.assertTrue(first.equals(second)); - Assert.assertTrue(first.equals(first)); - Assert.assertFalse(first.equals(new Object())); + assertEquals(first, second); + assertEquals(first, first); + assertNotEquals(first, new Object()); first.setDegrees(34); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); second.setDegrees(34); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); second.setUnit("v"); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); first.setUnit("v"); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); first.setGust(4); - Assert.assertFalse(first.equals(second)); + assertNotEquals(first, second); second.setGust(4); - Assert.assertTrue(first.equals(second)); + assertEquals(first, second); + + first.setSpeed(32); + + assertNotEquals(first, second); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastIntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastIntegrationTest.java index f085210..d9306c1 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastIntegrationTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastIntegrationTest.java @@ -31,12 +31,13 @@ import com.github.prominence.openweathermap.api.exception.NoDataFoundException; import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.forecast.Forecast; import com.github.prominence.openweathermap.api.model.forecast.WeatherForecast; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import static org.junit.jupiter.api.Assertions.*; + public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { @Test public void whenGetForecastByCityNameRequestAsJava_thenReturnNotNull() { @@ -49,17 +50,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -74,7 +74,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -88,7 +88,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -102,17 +102,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -127,7 +126,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -141,7 +140,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -155,17 +154,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -180,7 +178,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -193,7 +191,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -207,17 +205,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -232,7 +229,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -245,31 +242,30 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test public void whenGetForecastByCoordinatesRequestAsJava_thenReturnNotNull() { final Forecast forecast = getClient() .forecast5Day3HourStep() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .language(Language.ENGLISH) .unitSystem(UnitSystem.METRIC) .count(15) .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -277,27 +273,27 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { public void whenGetForecastByCoordinatesRequestAsJSON_thenReturnNotNull() { final String forecastJson = getClient() .forecast5Day3HourStep() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .language(Language.SPANISH) .unitSystem(UnitSystem.IMPERIAL) .count(15) .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test public void whenGetForecastByCoordinatesRequestAsXML_thenReturnNotNull() { final String forecastXml = getClient() .forecast5Day3HourStep() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .language(Language.ENGLISH) .unitSystem(UnitSystem.METRIC) .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -311,17 +307,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -336,7 +331,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -349,7 +344,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -363,17 +358,16 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(forecast); - Assert.assertNotNull(forecast.getLocation()); - Assert.assertNotNull(forecast.getWeatherForecasts()); + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); for (WeatherForecast weatherForecast : forecast.getWeatherForecasts()) { - Assert.assertNotNull(weatherForecast.getState()); - Assert.assertNotNull(weatherForecast.getDescription()); - Assert.assertNotNull(weatherForecast.getForecastTime()); - Assert.assertNotNull(weatherForecast.getTemperature()); - Assert.assertNotNull(weatherForecast.getAtmosphericPressure()); - Assert.assertNotNull(weatherForecast.getHumidity()); - Assert.assertNotNull(weatherForecast.getWind()); + assertNotNull(weatherForecast.getWeatherState()); + assertNotNull(weatherForecast.getForecastTime()); + assertNotNull(weatherForecast.getTemperature()); + assertNotNull(weatherForecast.getAtmosphericPressure()); + assertNotNull(weatherForecast.getHumidity()); + assertNotNull(weatherForecast.getWind()); } } @@ -388,7 +382,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(forecastJson.startsWith("{")); + assertTrue(forecastJson.startsWith("{")); } @Test @@ -401,7 +395,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(forecastXml.startsWith("<")); + assertTrue(forecastXml.startsWith("<")); } @Test @@ -415,7 +409,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieveAsync() .asJava(); - Assert.assertNotNull(forecastFuture); + assertNotNull(forecastFuture); System.out.println(forecastFuture.get()); } @@ -430,7 +424,7 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieveAsync() .asJSON(); - Assert.assertNotNull(forecastFuture); + assertNotNull(forecastFuture); System.out.println(forecastFuture.get()); } @@ -445,26 +439,30 @@ public class FiveDayThreeHourStepForecastIntegrationTest extends ApiTest { .retrieveAsync() .asXML(); - Assert.assertNotNull(forecastFuture); + assertNotNull(forecastFuture); System.out.println(forecastFuture.get()); } - @Test(expected = InvalidAuthTokenException.class) + @Test public void whenRequestCurrentWeatherWithInvalidApiKey_thenThrowAnException() { OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey"); - client - .forecast5Day3HourStep() - .byCityId(350001514) - .retrieve() - .asJSON(); + assertThrows(InvalidAuthTokenException.class, () -> + client + .forecast5Day3HourStep() + .byCityId(350001514) + .retrieve() + .asJSON() + ); } - @Test(expected = NoDataFoundException.class) + @Test public void whenRequestCurrentWeatherForInvalidLocation_thenThrowAnException() { - getClient() - .forecast5Day3HourStep() - .byCityName("invalidCity") - .retrieve() - .asJava(); + assertThrows(NoDataFoundException.class, () -> + getClient() + .forecast5Day3HourStep() + .byCityName("invalidCity") + .retrieve() + .asJava() + ); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapperUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapperUnitTest.java new file mode 100644 index 0000000..502198c --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/request/forecast/free/FiveDayThreeHourStepForecastResponseMapperUnitTest.java @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.forecast.free; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.forecast.Forecast; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class FiveDayThreeHourStepForecastResponseMapperUnitTest { + @Test + public void mapToForecast_invalidJSON() { + final String jsonString = "{\"cod\":\"200\",\"message:0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + + assertThrows(RuntimeException.class, () -> new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.IMPERIAL).mapToForecast(jsonString)); + } + + @Test + public void mapToForecast_whenSysNodeIsNotSet() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + forecast.getWeatherForecasts().forEach(weatherForecast -> assertNull(weatherForecast.getDayTime())); + } + + @Test + public void mapToForest_whenWeatherStateIsNotSet() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + forecast.getWeatherForecasts().forEach(weatherForecast -> assertNull(weatherForecast.getWeatherState())); + } + + @Test + public void mapToForest_withTemperatureVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + forecast.getWeatherForecasts().forEach(weatherForecast -> assertNotNull(weatherForecast.getTemperature())); + } + + @Test + public void mapToForest_withPressureVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + forecast.getWeatherForecasts().forEach(weatherForecast -> assertNotNull(weatherForecast.getAtmosphericPressure())); + } + + @Test + public void mapToForest_withWindVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + forecast.getWeatherForecasts().forEach(weatherForecast -> assertNotNull(weatherForecast.getWind())); + } + + @Test + public void mapToForest_withRainVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"rain\":{\"3h\":2.44},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"rain\":{},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + assertEquals(2.44, forecast.getWeatherForecasts().get(0).getRain().getThreeHourLevel(), 0.00001); + forecast.getWeatherForecasts().stream().skip(1).forEach(weatherForecast -> assertNull(weatherForecast.getRain())); + } + + @Test + public void mapToForest_withSnowVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"snow\":{\"3h\":2.44},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"snow\":{},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + assertEquals(2.44, forecast.getWeatherForecasts().get(0).getSnow().getThreeHourLevel(), 0.00001); + forecast.getWeatherForecasts().stream().skip(1).forEach(weatherForecast -> assertNull(weatherForecast.getSnow())); + } + + @Test + public void mapToForest_withCloudsVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619},\"country\":\"BY\",\"population\":0,\"timezone\":10800,\"sunrise\":1617938579,\"sunset\":1617987553}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + assertNull(forecast.getWeatherForecasts().get(0).getClouds()); + forecast.getWeatherForecasts().stream().skip(1).forEach(weatherForecast -> assertNotNull(weatherForecast.getClouds())); + } + + @Test + public void mapToForest_withLocationVariants() { + final String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\"}}"; + final Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getWeatherForecasts()); + } + + @Test + public void mapToForest_withCoordinateVariants() { + String jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023,\"lon\":27.5619}}}"; + Forecast forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNotNull(forecast.getLocation().getCoordinate()); + + jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lon\":27.5619}}}"; + forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNull(forecast.getLocation().getCoordinate()); + + jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{\"lat\":53.9023}}}"; + forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNull(forecast.getLocation().getCoordinate()); + + jsonString = "{\"cod\":\"200\",\"message\":0,\"cnt\":15,\"list\":[{\"dt\":1618002000,\"main\":{\"temp\":3.77,\"feels_like\":-0.66,\"temp_min\":3.59,\"temp_max\":3.77,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":64,\"temp_kf\":0.18},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}],\"clouds\":{\"all\":47},\"wind\":{\"speed\":5.99,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-09 21:00:00\"},{\"dt\":1618012800,\"main\":{\"temp\":3.12,\"feels_like\":-1.31,\"temp_min\":2.89,\"temp_max\":3.12,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":994,\"humidity\":69,\"temp_kf\":0.23},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":77},\"wind\":{\"speed\":5.61,\"deg\":192},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 00:00:00\"},{\"dt\":1618023600,\"main\":{\"temp\":2.13,\"feels_like\":-2.49,\"temp_min\":2.01,\"temp_max\":2.13,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":75,\"temp_kf\":0.12},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":94},\"wind\":{\"speed\":5.46,\"deg\":188},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 03:00:00\"},{\"dt\":1618034400,\"main\":{\"temp\":3.74,\"feels_like\":-1.01,\"temp_min\":3.74,\"temp_max\":3.74,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":70,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":6.75,\"deg\":189},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 06:00:00\"},{\"dt\":1618045200,\"main\":{\"temp\":8.81,\"feels_like\":5.15,\"temp_min\":8.81,\"temp_max\":8.81,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":993,\"humidity\":53,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":61},\"wind\":{\"speed\":7.91,\"deg\":198},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 09:00:00\"},{\"dt\":1618056000,\"main\":{\"temp\":11.76,\"feels_like\":10.19,\"temp_min\":11.76,\"temp_max\":11.76,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":46,\"temp_kf\":0},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":64},\"wind\":{\"speed\":8.24,\"deg\":210},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 12:00:00\"},{\"dt\":1618066800,\"main\":{\"temp\":11.48,\"feels_like\":10.09,\"temp_min\":11.48,\"temp_max\":11.48,\"pressure\":1018,\"sea_level\":1018,\"grnd_level\":993,\"humidity\":54,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":86},\"wind\":{\"speed\":5.45,\"deg\":213},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-10 15:00:00\"},{\"dt\":1618077600,\"main\":{\"temp\":9.1,\"feels_like\":7.02,\"temp_min\":9.1,\"temp_max\":9.1,\"pressure\":1019,\"sea_level\":1019,\"grnd_level\":994,\"humidity\":66,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":3.74,\"deg\":186},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 18:00:00\"},{\"dt\":1618088400,\"main\":{\"temp\":7.53,\"feels_like\":5.06,\"temp_min\":7.53,\"temp_max\":7.53,\"pressure\":1020,\"sea_level\":1020,\"grnd_level\":995,\"humidity\":71,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":95},\"wind\":{\"speed\":3.83,\"deg\":199},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-10 21:00:00\"},{\"dt\":1618099200,\"main\":{\"temp\":6.68,\"feels_like\":4.64,\"temp_min\":6.68,\"temp_max\":6.68,\"pressure\":1022,\"sea_level\":1022,\"grnd_level\":996,\"humidity\":77,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":92},\"wind\":{\"speed\":2.84,\"deg\":206},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 00:00:00\"},{\"dt\":1618110000,\"main\":{\"temp\":5.83,\"feels_like\":3.27,\"temp_min\":5.83,\"temp_max\":5.83,\"pressure\":1023,\"sea_level\":1023,\"grnd_level\":997,\"humidity\":81,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"clouds\":{\"all\":96},\"wind\":{\"speed\":3.34,\"deg\":186},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"n\"},\"dt_txt\":\"2021-04-11 03:00:00\"},{\"dt\":1618120800,\"main\":{\"temp\":7.31,\"feels_like\":4.64,\"temp_min\":7.31,\"temp_max\":7.31,\"pressure\":1024,\"sea_level\":1024,\"grnd_level\":998,\"humidity\":76,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":98},\"wind\":{\"speed\":4.12,\"deg\":196},\"visibility\":10000,\"pop\":0.02,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 06:00:00\"},{\"dt\":1618131600,\"main\":{\"temp\":11,\"feels_like\":9.83,\"temp_min\":11,\"temp_max\":11,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":64,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":4.69,\"deg\":194},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 09:00:00\"},{\"dt\":1618142400,\"main\":{\"temp\":14.78,\"feels_like\":13.59,\"temp_min\":14.78,\"temp_max\":14.78,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":49,\"temp_kf\":0},\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":{\"all\":100},\"wind\":{\"speed\":5.6,\"deg\":190},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 12:00:00\"},{\"dt\":1618153200,\"main\":{\"temp\":14.58,\"feels_like\":13.4,\"temp_min\":14.58,\"temp_max\":14.58,\"pressure\":1025,\"sea_level\":1025,\"grnd_level\":1000,\"humidity\":50,\"temp_kf\":0},\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"clouds\":{\"all\":30},\"wind\":{\"speed\":4.77,\"deg\":177},\"visibility\":10000,\"pop\":0,\"sys\":{\"pod\":\"d\"},\"dt_txt\":\"2021-04-11 15:00:00\"}],\"city\":{\"id\":350001514,\"name\":\"Minsk\",\"coord\":{}}}"; + forecast = new FiveDayThreeHourStepForecastResponseMapper(UnitSystem.METRIC).mapToForecast(jsonString); + + assertNotNull(forecast); + assertNotNull(forecast.getLocation()); + assertNull(forecast.getLocation().getCoordinate()); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapperUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapperUnitTest.java new file mode 100644 index 0000000..293a4fe --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/OneCallWeatherResponseMapperUnitTest.java @@ -0,0 +1,137 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +public class OneCallWeatherResponseMapperUnitTest { + @Test + public void mapToCurrent() { // TODO: remove + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"hourly\":[{\"dt\":1618048800,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":7.72,\"wind_deg\":200,\"wind_gust\":10.55,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618052400,\"temp\":11.6,\"feels_like\":9.96,\"pressure\":1018,\"humidity\":44,\"dew_point\":-0.2,\"uvi\":3.22,\"clouds\":32,\"visibility\":10000,\"wind_speed\":7.76,\"wind_deg\":202,\"wind_gust\":10.75,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618056000,\"temp\":12.26,\"feels_like\":10.72,\"pressure\":1018,\"humidity\":45,\"dew_point\":0.68,\"uvi\":2.67,\"clouds\":49,\"visibility\":10000,\"wind_speed\":7.66,\"wind_deg\":205,\"wind_gust\":10.76,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618059600,\"temp\":12.86,\"feels_like\":11.4,\"pressure\":1018,\"humidity\":46,\"dew_point\":1.53,\"uvi\":1.22,\"clouds\":19,\"visibility\":10000,\"wind_speed\":7.15,\"wind_deg\":210,\"wind_gust\":9.99,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618063200,\"temp\":13.04,\"feels_like\":11.68,\"pressure\":1018,\"humidity\":49,\"dew_point\":2.58,\"uvi\":0.7,\"clouds\":50,\"visibility\":10000,\"wind_speed\":5.95,\"wind_deg\":210,\"wind_gust\":9.4,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618066800,\"temp\":12.53,\"feels_like\":11.2,\"pressure\":1018,\"humidity\":52,\"dew_point\":3.07,\"uvi\":0.32,\"clouds\":48,\"visibility\":10000,\"wind_speed\":5.43,\"wind_deg\":209,\"wind_gust\":9.32,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618070400,\"temp\":11.02,\"feels_like\":9.72,\"pressure\":1018,\"humidity\":59,\"dew_point\":3.37,\"uvi\":0.12,\"clouds\":51,\"visibility\":10000,\"wind_speed\":4.22,\"wind_deg\":200,\"wind_gust\":8.94,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618074000,\"temp\":8.81,\"feels_like\":6.7,\"pressure\":1019,\"humidity\":67,\"dew_point\":3.23,\"uvi\":0,\"clouds\":55,\"visibility\":10000,\"wind_speed\":3.67,\"wind_deg\":184,\"wind_gust\":8.41,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618077600,\"temp\":7.94,\"feels_like\":5.47,\"pressure\":1020,\"humidity\":71,\"dew_point\":3.06,\"uvi\":0,\"clouds\":59,\"visibility\":10000,\"wind_speed\":4,\"wind_deg\":177,\"wind_gust\":10.47,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618081200,\"temp\":7.68,\"feels_like\":4.81,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.92,\"uvi\":0,\"clouds\":79,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":179,\"wind_gust\":12.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618084800,\"temp\":7.78,\"feels_like\":4.76,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.89,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":5.12,\"wind_deg\":185,\"wind_gust\":13.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618088400,\"temp\":7.45,\"feels_like\":4.33,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.77,\"uvi\":0,\"clouds\":86,\"visibility\":10000,\"wind_speed\":5.17,\"wind_deg\":190,\"wind_gust\":13.37,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618092000,\"temp\":6.97,\"feels_like\":3.85,\"pressure\":1021,\"humidity\":74,\"dew_point\":2.67,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":4.89,\"wind_deg\":192,\"wind_gust\":12.68,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618095600,\"temp\":6.46,\"feels_like\":3.4,\"pressure\":1021,\"humidity\":76,\"dew_point\":2.7,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":191,\"wind_gust\":11.89,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618099200,\"temp\":5.96,\"feels_like\":2.9,\"pressure\":1021,\"humidity\":79,\"dew_point\":2.65,\"uvi\":0,\"clouds\":91,\"visibility\":10000,\"wind_speed\":4.26,\"wind_deg\":188,\"wind_gust\":11.23,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618102800,\"temp\":5.31,\"feels_like\":2.22,\"pressure\":1022,\"humidity\":81,\"dew_point\":2.47,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.04,\"wind_deg\":186,\"wind_gust\":10.72,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618106400,\"temp\":5.2,\"feels_like\":2.18,\"pressure\":1022,\"humidity\":82,\"dew_point\":2.41,\"uvi\":0,\"clouds\":95,\"visibility\":10000,\"wind_speed\":3.87,\"wind_deg\":190,\"wind_gust\":10.92,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618110000,\"temp\":4.56,\"feels_like\":1.51,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.29,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":3.69,\"wind_deg\":186,\"wind_gust\":10.33,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618113600,\"temp\":4.51,\"feels_like\":1.64,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.33,\"uvi\":0,\"clouds\":84,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":191,\"wind_gust\":10.18,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618117200,\"temp\":6.05,\"feels_like\":3.41,\"pressure\":1024,\"humidity\":80,\"dew_point\":2.89,\"uvi\":0.15,\"clouds\":80,\"visibility\":10000,\"wind_speed\":3.55,\"wind_deg\":193,\"wind_gust\":10.09,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618120800,\"temp\":7.96,\"feels_like\":5.31,\"pressure\":1024,\"humidity\":72,\"dew_point\":3.29,\"uvi\":0.38,\"clouds\":80,\"visibility\":10000,\"wind_speed\":4.39,\"wind_deg\":197,\"wind_gust\":8.53,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618124400,\"temp\":9.61,\"feels_like\":7.3,\"pressure\":1024,\"humidity\":67,\"dew_point\":3.88,\"uvi\":1.01,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":197,\"wind_gust\":7.77,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618128000,\"temp\":11.14,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":62,\"dew_point\":4.27,\"uvi\":1.54,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":198,\"wind_gust\":7.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618131600,\"temp\":12.8,\"feels_like\":11.62,\"pressure\":1025,\"humidity\":57,\"dew_point\":4.57,\"uvi\":1.97,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.87,\"wind_deg\":196,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618135200,\"temp\":14.03,\"feels_like\":12.87,\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"uvi\":3.09,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.11,\"wind_deg\":194,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618138800,\"temp\":14.82,\"feels_like\":13.66,\"pressure\":1025,\"humidity\":50,\"dew_point\":4.62,\"uvi\":2.96,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.32,\"wind_deg\":191,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618142400,\"temp\":15.64,\"feels_like\":14.49,\"pressure\":1025,\"humidity\":47,\"dew_point\":4.48,\"uvi\":2.45,\"clouds\":94,\"visibility\":10000,\"wind_speed\":5.42,\"wind_deg\":192,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618146000,\"temp\":15.81,\"feels_like\":14.62,\"pressure\":1024,\"humidity\":45,\"dew_point\":4.15,\"uvi\":2.02,\"clouds\":24,\"visibility\":10000,\"wind_speed\":5.15,\"wind_deg\":193,\"wind_gust\":6.3,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618149600,\"temp\":15.71,\"feels_like\":14.51,\"pressure\":1025,\"humidity\":45,\"dew_point\":3.87,\"uvi\":1.17,\"clouds\":48,\"visibility\":10000,\"wind_speed\":4.79,\"wind_deg\":188,\"wind_gust\":6.01,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618153200,\"temp\":14.79,\"feels_like\":13.63,\"pressure\":1024,\"humidity\":50,\"dew_point\":4.71,\"uvi\":0.53,\"clouds\":63,\"visibility\":10000,\"wind_speed\":3.73,\"wind_deg\":177,\"wind_gust\":6.35,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618156800,\"temp\":12.85,\"feels_like\":11.73,\"pressure\":1024,\"humidity\":59,\"dew_point\":5.18,\"uvi\":0.17,\"clouds\":72,\"visibility\":10000,\"wind_speed\":3.05,\"wind_deg\":159,\"wind_gust\":6.38,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618160400,\"temp\":10.92,\"feels_like\":9.71,\"pressure\":1025,\"humidity\":63,\"dew_point\":4.26,\"uvi\":0,\"clouds\":78,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":152,\"wind_gust\":6.64,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618164000,\"temp\":9.65,\"feels_like\":7.72,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.66,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":3.68,\"wind_deg\":148,\"wind_gust\":9.04,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618167600,\"temp\":8.82,\"feels_like\":6.59,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.05,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.92,\"wind_deg\":147,\"wind_gust\":11.02,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618171200,\"temp\":8.07,\"feels_like\":5.87,\"pressure\":1026,\"humidity\":67,\"dew_point\":2.43,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.54,\"wind_deg\":154,\"wind_gust\":11.12,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618174800,\"temp\":7.24,\"feels_like\":4.99,\"pressure\":1027,\"humidity\":68,\"dew_point\":1.96,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.32,\"wind_deg\":154,\"wind_gust\":10.55,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618178400,\"temp\":6.58,\"feels_like\":4.31,\"pressure\":1027,\"humidity\":70,\"dew_point\":1.65,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.14,\"wind_deg\":154,\"wind_gust\":9.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618182000,\"temp\":6.03,\"feels_like\":3.57,\"pressure\":1027,\"humidity\":71,\"dew_point\":1.26,\"uvi\":0,\"clouds\":82,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":150,\"wind_gust\":8.44,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618185600,\"temp\":5.51,\"feels_like\":2.94,\"pressure\":1027,\"humidity\":72,\"dew_point\":0.95,\"uvi\":0,\"clouds\":71,\"visibility\":10000,\"wind_speed\":3.26,\"wind_deg\":150,\"wind_gust\":8.58,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618189200,\"temp\":5,\"feels_like\":2.29,\"pressure\":1027,\"humidity\":74,\"dew_point\":0.72,\"uvi\":0,\"clouds\":9,\"visibility\":10000,\"wind_speed\":3.3,\"wind_deg\":147,\"wind_gust\":8.63,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"pop\":0},{\"dt\":1618192800,\"temp\":4.47,\"feels_like\":1.69,\"pressure\":1027,\"humidity\":75,\"dew_point\":0.52,\"uvi\":0,\"clouds\":14,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":145,\"wind_gust\":8.14,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618196400,\"temp\":4.03,\"feels_like\":1.08,\"pressure\":1026,\"humidity\":76,\"dew_point\":0.22,\"uvi\":0,\"clouds\":12,\"visibility\":10000,\"wind_speed\":3.36,\"wind_deg\":138,\"wind_gust\":8.13,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618200000,\"temp\":4,\"feels_like\":0.9,\"pressure\":1026,\"humidity\":75,\"dew_point\":0.13,\"uvi\":0.08,\"clouds\":10,\"visibility\":10000,\"wind_speed\":3.57,\"wind_deg\":131,\"wind_gust\":9.24,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618203600,\"temp\":5.73,\"feels_like\":2.73,\"pressure\":1026,\"humidity\":68,\"dew_point\":0.52,\"uvi\":0.33,\"clouds\":8,\"visibility\":10000,\"wind_speed\":4.05,\"wind_deg\":138,\"wind_gust\":10.36,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618207200,\"temp\":7.87,\"feels_like\":4.9,\"pressure\":1025,\"humidity\":59,\"dew_point\":0.53,\"uvi\":0.84,\"clouds\":7,\"visibility\":10000,\"wind_speed\":5.05,\"wind_deg\":145,\"wind_gust\":10.48,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618210800,\"temp\":9.9,\"feels_like\":7.29,\"pressure\":1025,\"humidity\":53,\"dew_point\":0.8,\"uvi\":1.56,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.48,\"wind_deg\":147,\"wind_gust\":9.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618214400,\"temp\":11.5,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":47,\"dew_point\":0.86,\"uvi\":2.37,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.94,\"wind_deg\":152,\"wind_gust\":8.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618218000,\"temp\":12.64,\"feels_like\":11.08,\"pressure\":1024,\"humidity\":43,\"dew_point\":0.68,\"uvi\":3.04,\"clouds\":0,\"visibility\":10000,\"wind_speed\":6.25,\"wind_deg\":151,\"wind_gust\":8.5,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0}],\"daily\":[{\"dt\":1618048800,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":{\"day\":11.84,\"min\":1.69,\"max\":13.04,\"night\":7.78,\"eve\":11.02,\"morn\":1.69},\"feels_like\":{\"day\":10.12,\"night\":-2.86,\"eve\":9.72,\"morn\":-2.86},\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"wind_speed\":7.72,\"wind_deg\":200,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.36},{\"dt\":1618135200,\"sunrise\":1618111186,\"sunset\":1618160588,\"temp\":{\"day\":14.03,\"min\":4.51,\"max\":15.81,\"night\":8.07,\"eve\":12.85,\"morn\":4.51},\"feels_like\":{\"day\":12.87,\"night\":1.64,\"eve\":11.73,\"morn\":1.64},\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"wind_speed\":5.11,\"wind_deg\":194,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":100,\"pop\":0,\"uvi\":3.09},{\"dt\":1618221600,\"sunrise\":1618197445,\"sunset\":1618247098,\"temp\":{\"day\":13.62,\"min\":4,\"max\":14.94,\"night\":7.62,\"eve\":12.21,\"morn\":4},\"feels_like\":{\"day\":12.08,\"night\":0.9,\"eve\":10.87,\"morn\":0.9},\"pressure\":1024,\"humidity\":40,\"dew_point\":0.58,\"wind_speed\":6.09,\"wind_deg\":152,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.11},{\"dt\":1618308000,\"sunrise\":1618283705,\"sunset\":1618333607,\"temp\":{\"day\":14.42,\"min\":4.45,\"max\":16.91,\"night\":11.72,\"eve\":16.64,\"morn\":4.45},\"feels_like\":{\"day\":13.17,\"night\":2.28,\"eve\":15.43,\"morn\":2.28},\"pressure\":1019,\"humidity\":48,\"dew_point\":3.67,\"wind_speed\":3.07,\"wind_deg\":153,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":8,\"pop\":0,\"uvi\":3.53},{\"dt\":1618394400,\"sunrise\":1618369965,\"sunset\":1618420117,\"temp\":{\"day\":10.12,\"min\":7.84,\"max\":10.7,\"night\":8.87,\"eve\":9.78,\"morn\":7.84},\"feels_like\":{\"day\":9.54,\"night\":6.26,\"eve\":8.02,\"morn\":6.26},\"pressure\":1012,\"humidity\":90,\"dew_point\":8.65,\"wind_speed\":3.6,\"wind_deg\":129,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.98,\"rain\":2.37,\"uvi\":2.7},{\"dt\":1618480800,\"sunrise\":1618456226,\"sunset\":1618506627,\"temp\":{\"day\":8.88,\"min\":6.86,\"max\":10.63,\"night\":8.88,\"eve\":10.63,\"morn\":6.86},\"feels_like\":{\"day\":7.04,\"night\":5.16,\"eve\":9.81,\"morn\":5.16},\"pressure\":1011,\"humidity\":86,\"dew_point\":6.85,\"wind_speed\":3.22,\"wind_deg\":98,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.91,\"rain\":4.23,\"uvi\":3},{\"dt\":1618567200,\"sunrise\":1618542488,\"sunset\":1618593137,\"temp\":{\"day\":5.06,\"min\":4.81,\"max\":8.16,\"night\":4.84,\"eve\":7.24,\"morn\":5.39},\"feels_like\":{\"day\":2.81,\"night\":1.18,\"eve\":6.67,\"morn\":1.18},\"pressure\":1010,\"humidity\":91,\"dew_point\":3.81,\"wind_speed\":2.69,\"wind_deg\":101,\"weather\":[{\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":1,\"rain\":15.37,\"uvi\":3},{\"dt\":1618653600,\"sunrise\":1618628751,\"sunset\":1618679646,\"temp\":{\"day\":3.07,\"min\":1.88,\"max\":5.32,\"night\":1.88,\"eve\":2.04,\"morn\":4.62},\"feels_like\":{\"day\":-0.42,\"night\":1.75,\"eve\":-1.74,\"morn\":1.75},\"pressure\":1010,\"humidity\":97,\"dew_point\":2.74,\"wind_speed\":3.86,\"wind_deg\":287,\"weather\":[{\"id\":616,\"main\":\"Snow\",\"description\":\"rain and snow\",\"icon\":\"13d\"}],\"clouds\":100,\"pop\":1,\"rain\":6.67,\"snow\":8.83,\"uvi\":3}]}"; + } + + @Test + public void mapToCurrent_withInvalidJSON() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"hourly\":[{\"dt\":1618048800,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":7.72,\"wind_deg\":200,\"wind_gust\":10.55,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618052400,\"temp\":11.6,\"feels_like\":9.96,\"pressure\":1018,\"humidity\":44,\"dew_point\":-0.2,\"uvi\":3.22,\"clouds\":32,\"visibility\":10000,\"wind_speed\":7.76,\"wind_deg\":202,\"wind_gust\":10.75,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618056000,\"temp\":12.26,\"feels_like\":10.72,\"pressure\":1018,\"humidity\":45,\"dew_point\":0.68,\"uvi\":2.67,\"clouds\":49,\"visibility\":10000,\"wind_speed\":7.66,\"wind_deg\":205,\"wind_gust\":10.76,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618059600,\"temp\":12.86,\"feels_like\":11.4,\"pressure\":1018,\"humidity\":46,\"dew_point\":1.53,\"uvi\":1.22,\"clouds\":19,\"visibility\":10000,\"wind_speed\":7.15,\"wind_deg\":210,\"wind_gust\":9.99,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618063200,\"temp\":13.04,\"feels_like\":11.68,\"pressure\":1018,\"humidity\":49,\"dew_point\":2.58,\"uvi\":0.7,\"clouds\":50,\"visibility\":10000,\"wind_speed\":5.95,\"wind_deg\":210,\"wind_gust\":9.4,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618066800,\"temp\":12.53,\"feels_like\":11.2,\"pressure\":1018,\"humidity\":52,\"dew_point\":3.07,\"uvi\":0.32,\"clouds\":48,\"visibility\":10000,\"wind_speed\":5.43,\"wind_deg\":209,\"wind_gust\":9.32,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618070400,\"temp\":11.02,\"feels_like\":9.72,\"pressure\":1018,\"humidity\":59,\"dew_point\":3.37,\"uvi\":0.12,\"clouds\":51,\"visibility\":10000,\"wind_speed\":4.22,\"wind_deg\":200,\"wind_gust\":8.94,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618074000,\"temp\":8.81,\"feels_like\":6.7,\"pressure\":1019,\"humidity\":67,\"dew_point\":3.23,\"uvi\":0,\"clouds\":55,\"visibility\":10000,\"wind_speed\":3.67,\"wind_deg\":184,\"wind_gust\":8.41,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618077600,\"temp\":7.94,\"feels_like\":5.47,\"pressure\":1020,\"humidity\":71,\"dew_point\":3.06,\"uvi\":0,\"clouds\":59,\"visibility\":10000,\"wind_speed\":4,\"wind_deg\":177,\"wind_gust\":10.47,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618081200,\"temp\":7.68,\"feels_like\":4.81,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.92,\"uvi\":0,\"clouds\":79,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":179,\"wind_gust\":12.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618084800,\"temp\":7.78,\"feels_like\":4.76,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.89,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":5.12,\"wind_deg\":185,\"wind_gust\":13.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618088400,\"temp\":7.45,\"feels_like\":4.33,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.77,\"uvi\":0,\"clouds\":86,\"visibility\":10000,\"wind_speed\":5.17,\"wind_deg\":190,\"wind_gust\":13.37,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618092000,\"temp\":6.97,\"feels_like\":3.85,\"pressure\":1021,\"humidity\":74,\"dew_point\":2.67,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":4.89,\"wind_deg\":192,\"wind_gust\":12.68,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618095600,\"temp\":6.46,\"feels_like\":3.4,\"pressure\":1021,\"humidity\":76,\"dew_point\":2.7,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":191,\"wind_gust\":11.89,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618099200,\"temp\":5.96,\"feels_like\":2.9,\"pressure\":1021,\"humidity\":79,\"dew_point\":2.65,\"uvi\":0,\"clouds\":91,\"visibility\":10000,\"wind_speed\":4.26,\"wind_deg\":188,\"wind_gust\":11.23,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618102800,\"temp\":5.31,\"feels_like\":2.22,\"pressure\":1022,\"humidity\":81,\"dew_point\":2.47,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.04,\"wind_deg\":186,\"wind_gust\":10.72,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618106400,\"temp\":5.2,\"feels_like\":2.18,\"pressure\":1022,\"humidity\":82,\"dew_point\":2.41,\"uvi\":0,\"clouds\":95,\"visibility\":10000,\"wind_speed\":3.87,\"wind_deg\":190,\"wind_gust\":10.92,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618110000,\"temp\":4.56,\"feels_like\":1.51,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.29,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":3.69,\"wind_deg\":186,\"wind_gust\":10.33,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618113600,\"temp\":4.51,\"feels_like\":1.64,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.33,\"uvi\":0,\"clouds\":84,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":191,\"wind_gust\":10.18,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618117200,\"temp\":6.05,\"feels_like\":3.41,\"pressure\":1024,\"humidity\":80,\"dew_point\":2.89,\"uvi\":0.15,\"clouds\":80,\"visibility\":10000,\"wind_speed\":3.55,\"wind_deg\":193,\"wind_gust\":10.09,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618120800,\"temp\":7.96,\"feels_like\":5.31,\"pressure\":1024,\"humidity\":72,\"dew_point\":3.29,\"uvi\":0.38,\"clouds\":80,\"visibility\":10000,\"wind_speed\":4.39,\"wind_deg\":197,\"wind_gust\":8.53,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618124400,\"temp\":9.61,\"feels_like\":7.3,\"pressure\":1024,\"humidity\":67,\"dew_point\":3.88,\"uvi\":1.01,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":197,\"wind_gust\":7.77,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618128000,\"temp\":11.14,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":62,\"dew_point\":4.27,\"uvi\":1.54,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":198,\"wind_gust\":7.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618131600,\"temp\":12.8,\"feels_like\":11.62,\"pressure\":1025,\"humidity\":57,\"dew_point\":4.57,\"uvi\":1.97,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.87,\"wind_deg\":196,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618135200,\"temp\":14.03,\"feels_like\":12.87,\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"uvi\":3.09,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.11,\"wind_deg\":194,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618138800,\"temp\":14.82,\"feels_like\":13.66,\"pressure\":1025,\"humidity\":50,\"dew_point\":4.62,\"uvi\":2.96,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.32,\"wind_deg\":191,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618142400,\"temp\":15.64,\"feels_like\":14.49,\"pressure\":1025,\"humidity\":47,\"dew_point\":4.48,\"uvi\":2.45,\"clouds\":94,\"visibility\":10000,\"wind_speed\":5.42,\"wind_deg\":192,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618146000,\"temp\":15.81,\"feels_like\":14.62,\"pressure\":1024,\"humidity\":45,\"dew_point\":4.15,\"uvi\":2.02,\"clouds\":24,\"visibility\":10000,\"wind_speed\":5.15,\"wind_deg\":193,\"wind_gust\":6.3,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618149600,\"temp\":15.71,\"feels_like\":14.51,\"pressure\":1025,\"humidity\":45,\"dew_point\":3.87,\"uvi\":1.17,\"clouds\":48,\"visibility\":10000,\"wind_speed\":4.79,\"wind_deg\":188,\"wind_gust\":6.01,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618153200,\"temp\":14.79,\"feels_like\":13.63,\"pressure\":1024,\"humidity\":50,\"dew_point\":4.71,\"uvi\":0.53,\"clouds\":63,\"visibility\":10000,\"wind_speed\":3.73,\"wind_deg\":177,\"wind_gust\":6.35,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618156800,\"temp\":12.85,\"feels_like\":11.73,\"pressure\":1024,\"humidity\":59,\"dew_point\":5.18,\"uvi\":0.17,\"clouds\":72,\"visibility\":10000,\"wind_speed\":3.05,\"wind_deg\":159,\"wind_gust\":6.38,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618160400,\"temp\":10.92,\"feels_like\":9.71,\"pressure\":1025,\"humidity\":63,\"dew_point\":4.26,\"uvi\":0,\"clouds\":78,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":152,\"wind_gust\":6.64,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618164000,\"temp\":9.65,\"feels_like\":7.72,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.66,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":3.68,\"wind_deg\":148,\"wind_gust\":9.04,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618167600,\"temp\":8.82,\"feels_like\":6.59,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.05,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.92,\"wind_deg\":147,\"wind_gust\":11.02,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618171200,\"temp\":8.07,\"feels_like\":5.87,\"pressure\":1026,\"humidity\":67,\"dew_point\":2.43,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.54,\"wind_deg\":154,\"wind_gust\":11.12,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618174800,\"temp\":7.24,\"feels_like\":4.99,\"pressure\":1027,\"humidity\":68,\"dew_point\":1.96,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.32,\"wind_deg\":154,\"wind_gust\":10.55,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618178400,\"temp\":6.58,\"feels_like\":4.31,\"pressure\":1027,\"humidity\":70,\"dew_point\":1.65,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.14,\"wind_deg\":154,\"wind_gust\":9.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618182000,\"temp\":6.03,\"feels_like\":3.57,\"pressure\":1027,\"humidity\":71,\"dew_point\":1.26,\"uvi\":0,\"clouds\":82,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":150,\"wind_gust\":8.44,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618185600,\"temp\":5.51,\"feels_like\":2.94,\"pressure\":1027,\"humidity\":72,\"dew_point\":0.95,\"uvi\":0,\"clouds\":71,\"visibility\":10000,\"wind_speed\":3.26,\"wind_deg\":150,\"wind_gust\":8.58,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618189200,\"temp\":5,\"feels_like\":2.29,\"pressure\":1027,\"humidity\":74,\"dew_point\":0.72,\"uvi\":0,\"clouds\":9,\"visibility\":10000,\"wind_speed\":3.3,\"wind_deg\":147,\"wind_gust\":8.63,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"pop\":0},{\"dt\":1618192800,\"temp\":4.47,\"feels_like\":1.69,\"pressure\":1027,\"humidity\":75,\"dew_point\":0.52,\"uvi\":0,\"clouds\":14,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":145,\"wind_gust\":8.14,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618196400,\"temp\":4.03,\"feels_like\":1.08,\"pressure\":1026,\"humidity\":76,\"dew_point\":0.22,\"uvi\":0,\"clouds\":12,\"visibility\":10000,\"wind_speed\":3.36,\"wind_deg\":138,\"wind_gust\":8.13,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618200000,\"temp\":4,\"feels_like\":0.9,\"pressure\":1026,\"humidity\":75,\"dew_point\":0.13,\"uvi\":0.08,\"clouds\":10,\"visibility\":10000,\"wind_speed\":3.57,\"wind_deg\":131,\"wind_gust\":9.24,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618203600,\"temp\":5.73,\"feels_like\":2.73,\"pressure\":1026,\"humidity\":68,\"dew_point\":0.52,\"uvi\":0.33,\"clouds\":8,\"visibility\":10000,\"wind_speed\":4.05,\"wind_deg\":138,\"wind_gust\":10.36,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618207200,\"temp\":7.87,\"feels_like\":4.9,\"pressure\":1025,\"humidity\":59,\"dew_point\":0.53,\"uvi\":0.84,\"clouds\":7,\"visibility\":10000,\"wind_speed\":5.05,\"wind_deg\":145,\"wind_gust\":10.48,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618210800,\"temp\":9.9,\"feels_like\":7.29,\"pressure\":1025,\"humidity\":53,\"dew_point\":0.8,\"uvi\":1.56,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.48,\"wind_deg\":147,\"wind_gust\":9.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618214400,\"temp\":11.5,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":47,\"dew_point\":0.86,\"uvi\":2.37,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.94,\"wind_deg\":152,\"wind_gust\":8.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618218000,\"temp\":12.64,\"feels_like\":11.08,\"pressure\":1024,\"humidity\":43,\"dew_point\":0.68,\"uvi\":3.04,\"clouds\":0,\"visibility\":10000,\"wind_speed\":6.25,\"wind_deg\":151,\"wind_gust\":8.5,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0}],\"daily\":[{\"dt\":1618048800,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":{\"day\":11.84,\"min\":1.69,\"max\":13.04,\"night\":7.78,\"eve\":11.02,\"morn\":1.69},\"feels_like\":{\"day\":10.12,\"night\":-2.86,\"eve\":9.72,\"morn\":-2.86},\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"wind_speed\":7.72,\"wind_deg\":200,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.36},{\"dt\":1618135200,\"sunrise\":1618111186,\"sunset\":1618160588,\"temp\":{\"day\":14.03,\"min\":4.51,\"max\":15.81,\"night\":8.07,\"eve\":12.85,\"morn\":4.51},\"feels_like\":{\"day\":12.87,\"night\":1.64,\"eve\":11.73,\"morn\":1.64},\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"wind_speed\":5.11,\"wind_deg\":194,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":100,\"pop\":0,\"uvi\":3.09},{\"dt\":1618221600,\"sunrise\":1618197445,\"sunset\":1618247098,\"temp\":{\"day\":13.62,\"min\":4,\"max\":14.94,\"night\":7.62,\"eve\":12.21,\"morn\":4},\"feels_like\":{\"day\":12.08,\"night\":0.9,\"eve\":10.87,\"morn\":0.9},\"pressure\":1024,\"humidity\":40,\"dew_point\":0.58,\"wind_speed\":6.09,\"wind_deg\":152,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.11},{\"dt\":1618308000,\"sunrise\":1618283705,\"sunset\":1618333607,\"temp\":{\"day\":14.42,\"min\":4.45,\"max\":16.91,\"night\":11.72,\"eve\":16.64,\"morn\":4.45},\"feels_like\":{\"day\":13.17,\"night\":2.28,\"eve\":15.43,\"morn\":2.28},\"pressure\":1019,\"humidity\":48,\"dew_point\":3.67,\"wind_speed\":3.07,\"wind_deg\":153,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":8,\"pop\":0,\"uvi\":3.53},{\"dt\":1618394400,\"sunrise\":1618369965,\"sunset\":1618420117,\"temp\":{\"day\":10.12,\"min\":7.84,\"max\":10.7,\"night\":8.87,\"eve\":9.78,\"morn\":7.84},\"feels_like\":{\"day\":9.54,\"night\":6.26,\"eve\":8.02,\"morn\":6.26},\"pressure\":1012,\"humidity\":90,\"dew_point\":8.65,\"wind_speed\":3.6,\"wind_deg\":129,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.98,\"rain\":2.37,\"uvi\":2.7},{\"dt\":1618480800,\"sunrise\":1618456226,\"sunset\":1618506627,\"temp\":{\"day\":8.88,\"min\":6.86,\"max\":10.63,\"night\":8.88,\"eve\":10.63,\"morn\":6.86},\"feels_like\":{\"day\":7.04,\"night\":5.16,\"eve\":9.81,\"morn\":5.16},\"pressure\":1011,\"humidity\":86,\"dew_point\":6.85,\"wind_speed\":3.22,\"wind_deg\":98,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.91,\"rain\":4.23,\"uvi\":3},{\"dt\":1618567200,\"sunrise\":1618542488,\"sunset\":1618593137,\"temp\":{\"day\":5.06,\"min\":4.81,\"max\":8.16,\"night\":4.84,\"eve\":7.24,\"morn\":5.39},\"feels_like\":{\"day\":2.81,\"night\":1.18,\"eve\":6.67,\"morn\":1.18},\"pressure\":1010,\"humidity\":91,\"dew_point\":3.81,\"wind_speed\":2.69,\"wind_deg\":101,\"weather\":[{\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":1,\"rain\":15.37,\"uvi\":3},{\"dt\":1618653600,\"sunrise\":1618628751,\"sunset\":1618679646,\"temp\":{\"day\":3.07,\"min\":1.88,\"max\":5.32,\"night\":1.88,\"eve\":2.04,\"morn\":4.62},\"feels_like\":{\"day\":-0.42,\"night\":1.75,\"eve\":-1.74,\"morn\":1.75},\"pressure\":1010,\"humidity\":97,\"dew_point\":2.74,\"wind_speed\":3.86,\"wind_deg\":287,\"weather\":[{\"id\":616,\"main\":\"Snow\",\"description\":\"rain and snow\",\"icon\":\"13d\"}],\"clouds\":100,\"pop\":1,\"rain\":6.67,\"snow\":8.83,\"uvi\":3}]}"; + assertThrows(RuntimeException.class, () -> new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString)); + } + + @Test + public void mapToCurrent_withCurrentVariants() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"hourly\":[{\"dt\":1618048800,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":7.72,\"wind_deg\":200,\"wind_gust\":10.55,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618052400,\"temp\":11.6,\"feels_like\":9.96,\"pressure\":1018,\"humidity\":44,\"dew_point\":-0.2,\"uvi\":3.22,\"clouds\":32,\"visibility\":10000,\"wind_speed\":7.76,\"wind_deg\":202,\"wind_gust\":10.75,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618056000,\"temp\":12.26,\"feels_like\":10.72,\"pressure\":1018,\"humidity\":45,\"dew_point\":0.68,\"uvi\":2.67,\"clouds\":49,\"visibility\":10000,\"wind_speed\":7.66,\"wind_deg\":205,\"wind_gust\":10.76,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618059600,\"temp\":12.86,\"feels_like\":11.4,\"pressure\":1018,\"humidity\":46,\"dew_point\":1.53,\"uvi\":1.22,\"clouds\":19,\"visibility\":10000,\"wind_speed\":7.15,\"wind_deg\":210,\"wind_gust\":9.99,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618063200,\"temp\":13.04,\"feels_like\":11.68,\"pressure\":1018,\"humidity\":49,\"dew_point\":2.58,\"uvi\":0.7,\"clouds\":50,\"visibility\":10000,\"wind_speed\":5.95,\"wind_deg\":210,\"wind_gust\":9.4,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618066800,\"temp\":12.53,\"feels_like\":11.2,\"pressure\":1018,\"humidity\":52,\"dew_point\":3.07,\"uvi\":0.32,\"clouds\":48,\"visibility\":10000,\"wind_speed\":5.43,\"wind_deg\":209,\"wind_gust\":9.32,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618070400,\"temp\":11.02,\"feels_like\":9.72,\"pressure\":1018,\"humidity\":59,\"dew_point\":3.37,\"uvi\":0.12,\"clouds\":51,\"visibility\":10000,\"wind_speed\":4.22,\"wind_deg\":200,\"wind_gust\":8.94,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618074000,\"temp\":8.81,\"feels_like\":6.7,\"pressure\":1019,\"humidity\":67,\"dew_point\":3.23,\"uvi\":0,\"clouds\":55,\"visibility\":10000,\"wind_speed\":3.67,\"wind_deg\":184,\"wind_gust\":8.41,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618077600,\"temp\":7.94,\"feels_like\":5.47,\"pressure\":1020,\"humidity\":71,\"dew_point\":3.06,\"uvi\":0,\"clouds\":59,\"visibility\":10000,\"wind_speed\":4,\"wind_deg\":177,\"wind_gust\":10.47,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618081200,\"temp\":7.68,\"feels_like\":4.81,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.92,\"uvi\":0,\"clouds\":79,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":179,\"wind_gust\":12.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618084800,\"temp\":7.78,\"feels_like\":4.76,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.89,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":5.12,\"wind_deg\":185,\"wind_gust\":13.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618088400,\"temp\":7.45,\"feels_like\":4.33,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.77,\"uvi\":0,\"clouds\":86,\"visibility\":10000,\"wind_speed\":5.17,\"wind_deg\":190,\"wind_gust\":13.37,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618092000,\"temp\":6.97,\"feels_like\":3.85,\"pressure\":1021,\"humidity\":74,\"dew_point\":2.67,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":4.89,\"wind_deg\":192,\"wind_gust\":12.68,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618095600,\"temp\":6.46,\"feels_like\":3.4,\"pressure\":1021,\"humidity\":76,\"dew_point\":2.7,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":191,\"wind_gust\":11.89,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618099200,\"temp\":5.96,\"feels_like\":2.9,\"pressure\":1021,\"humidity\":79,\"dew_point\":2.65,\"uvi\":0,\"clouds\":91,\"visibility\":10000,\"wind_speed\":4.26,\"wind_deg\":188,\"wind_gust\":11.23,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618102800,\"temp\":5.31,\"feels_like\":2.22,\"pressure\":1022,\"humidity\":81,\"dew_point\":2.47,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.04,\"wind_deg\":186,\"wind_gust\":10.72,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618106400,\"temp\":5.2,\"feels_like\":2.18,\"pressure\":1022,\"humidity\":82,\"dew_point\":2.41,\"uvi\":0,\"clouds\":95,\"visibility\":10000,\"wind_speed\":3.87,\"wind_deg\":190,\"wind_gust\":10.92,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618110000,\"temp\":4.56,\"feels_like\":1.51,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.29,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":3.69,\"wind_deg\":186,\"wind_gust\":10.33,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618113600,\"temp\":4.51,\"feels_like\":1.64,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.33,\"uvi\":0,\"clouds\":84,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":191,\"wind_gust\":10.18,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618117200,\"temp\":6.05,\"feels_like\":3.41,\"pressure\":1024,\"humidity\":80,\"dew_point\":2.89,\"uvi\":0.15,\"clouds\":80,\"visibility\":10000,\"wind_speed\":3.55,\"wind_deg\":193,\"wind_gust\":10.09,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618120800,\"temp\":7.96,\"feels_like\":5.31,\"pressure\":1024,\"humidity\":72,\"dew_point\":3.29,\"uvi\":0.38,\"clouds\":80,\"visibility\":10000,\"wind_speed\":4.39,\"wind_deg\":197,\"wind_gust\":8.53,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618124400,\"temp\":9.61,\"feels_like\":7.3,\"pressure\":1024,\"humidity\":67,\"dew_point\":3.88,\"uvi\":1.01,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":197,\"wind_gust\":7.77,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618128000,\"temp\":11.14,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":62,\"dew_point\":4.27,\"uvi\":1.54,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":198,\"wind_gust\":7.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618131600,\"temp\":12.8,\"feels_like\":11.62,\"pressure\":1025,\"humidity\":57,\"dew_point\":4.57,\"uvi\":1.97,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.87,\"wind_deg\":196,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618135200,\"temp\":14.03,\"feels_like\":12.87,\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"uvi\":3.09,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.11,\"wind_deg\":194,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618138800,\"temp\":14.82,\"feels_like\":13.66,\"pressure\":1025,\"humidity\":50,\"dew_point\":4.62,\"uvi\":2.96,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.32,\"wind_deg\":191,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618142400,\"temp\":15.64,\"feels_like\":14.49,\"pressure\":1025,\"humidity\":47,\"dew_point\":4.48,\"uvi\":2.45,\"clouds\":94,\"visibility\":10000,\"wind_speed\":5.42,\"wind_deg\":192,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618146000,\"temp\":15.81,\"feels_like\":14.62,\"pressure\":1024,\"humidity\":45,\"dew_point\":4.15,\"uvi\":2.02,\"clouds\":24,\"visibility\":10000,\"wind_speed\":5.15,\"wind_deg\":193,\"wind_gust\":6.3,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618149600,\"temp\":15.71,\"feels_like\":14.51,\"pressure\":1025,\"humidity\":45,\"dew_point\":3.87,\"uvi\":1.17,\"clouds\":48,\"visibility\":10000,\"wind_speed\":4.79,\"wind_deg\":188,\"wind_gust\":6.01,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618153200,\"temp\":14.79,\"feels_like\":13.63,\"pressure\":1024,\"humidity\":50,\"dew_point\":4.71,\"uvi\":0.53,\"clouds\":63,\"visibility\":10000,\"wind_speed\":3.73,\"wind_deg\":177,\"wind_gust\":6.35,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618156800,\"temp\":12.85,\"feels_like\":11.73,\"pressure\":1024,\"humidity\":59,\"dew_point\":5.18,\"uvi\":0.17,\"clouds\":72,\"visibility\":10000,\"wind_speed\":3.05,\"wind_deg\":159,\"wind_gust\":6.38,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618160400,\"temp\":10.92,\"feels_like\":9.71,\"pressure\":1025,\"humidity\":63,\"dew_point\":4.26,\"uvi\":0,\"clouds\":78,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":152,\"wind_gust\":6.64,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618164000,\"temp\":9.65,\"feels_like\":7.72,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.66,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":3.68,\"wind_deg\":148,\"wind_gust\":9.04,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618167600,\"temp\":8.82,\"feels_like\":6.59,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.05,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.92,\"wind_deg\":147,\"wind_gust\":11.02,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618171200,\"temp\":8.07,\"feels_like\":5.87,\"pressure\":1026,\"humidity\":67,\"dew_point\":2.43,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.54,\"wind_deg\":154,\"wind_gust\":11.12,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618174800,\"temp\":7.24,\"feels_like\":4.99,\"pressure\":1027,\"humidity\":68,\"dew_point\":1.96,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.32,\"wind_deg\":154,\"wind_gust\":10.55,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618178400,\"temp\":6.58,\"feels_like\":4.31,\"pressure\":1027,\"humidity\":70,\"dew_point\":1.65,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.14,\"wind_deg\":154,\"wind_gust\":9.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618182000,\"temp\":6.03,\"feels_like\":3.57,\"pressure\":1027,\"humidity\":71,\"dew_point\":1.26,\"uvi\":0,\"clouds\":82,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":150,\"wind_gust\":8.44,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618185600,\"temp\":5.51,\"feels_like\":2.94,\"pressure\":1027,\"humidity\":72,\"dew_point\":0.95,\"uvi\":0,\"clouds\":71,\"visibility\":10000,\"wind_speed\":3.26,\"wind_deg\":150,\"wind_gust\":8.58,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618189200,\"temp\":5,\"feels_like\":2.29,\"pressure\":1027,\"humidity\":74,\"dew_point\":0.72,\"uvi\":0,\"clouds\":9,\"visibility\":10000,\"wind_speed\":3.3,\"wind_deg\":147,\"wind_gust\":8.63,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"pop\":0},{\"dt\":1618192800,\"temp\":4.47,\"feels_like\":1.69,\"pressure\":1027,\"humidity\":75,\"dew_point\":0.52,\"uvi\":0,\"clouds\":14,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":145,\"wind_gust\":8.14,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618196400,\"temp\":4.03,\"feels_like\":1.08,\"pressure\":1026,\"humidity\":76,\"dew_point\":0.22,\"uvi\":0,\"clouds\":12,\"visibility\":10000,\"wind_speed\":3.36,\"wind_deg\":138,\"wind_gust\":8.13,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618200000,\"temp\":4,\"feels_like\":0.9,\"pressure\":1026,\"humidity\":75,\"dew_point\":0.13,\"uvi\":0.08,\"clouds\":10,\"visibility\":10000,\"wind_speed\":3.57,\"wind_deg\":131,\"wind_gust\":9.24,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618203600,\"temp\":5.73,\"feels_like\":2.73,\"pressure\":1026,\"humidity\":68,\"dew_point\":0.52,\"uvi\":0.33,\"clouds\":8,\"visibility\":10000,\"wind_speed\":4.05,\"wind_deg\":138,\"wind_gust\":10.36,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618207200,\"temp\":7.87,\"feels_like\":4.9,\"pressure\":1025,\"humidity\":59,\"dew_point\":0.53,\"uvi\":0.84,\"clouds\":7,\"visibility\":10000,\"wind_speed\":5.05,\"wind_deg\":145,\"wind_gust\":10.48,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618210800,\"temp\":9.9,\"feels_like\":7.29,\"pressure\":1025,\"humidity\":53,\"dew_point\":0.8,\"uvi\":1.56,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.48,\"wind_deg\":147,\"wind_gust\":9.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618214400,\"temp\":11.5,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":47,\"dew_point\":0.86,\"uvi\":2.37,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.94,\"wind_deg\":152,\"wind_gust\":8.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618218000,\"temp\":12.64,\"feels_like\":11.08,\"pressure\":1024,\"humidity\":43,\"dew_point\":0.68,\"uvi\":3.04,\"clouds\":0,\"visibility\":10000,\"wind_speed\":6.25,\"wind_deg\":151,\"wind_gust\":8.5,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0}],\"daily\":[{\"dt\":1618048800,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":{\"day\":11.84,\"min\":1.69,\"max\":13.04,\"night\":7.78,\"eve\":11.02,\"morn\":1.69},\"feels_like\":{\"day\":10.12,\"night\":-2.86,\"eve\":9.72,\"morn\":-2.86},\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"wind_speed\":7.72,\"wind_deg\":200,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.36},{\"dt\":1618135200,\"sunrise\":1618111186,\"sunset\":1618160588,\"temp\":{\"day\":14.03,\"min\":4.51,\"max\":15.81,\"night\":8.07,\"eve\":12.85,\"morn\":4.51},\"feels_like\":{\"day\":12.87,\"night\":1.64,\"eve\":11.73,\"morn\":1.64},\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"wind_speed\":5.11,\"wind_deg\":194,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":100,\"pop\":0,\"uvi\":3.09},{\"dt\":1618221600,\"sunrise\":1618197445,\"sunset\":1618247098,\"temp\":{\"day\":13.62,\"min\":4,\"max\":14.94,\"night\":7.62,\"eve\":12.21,\"morn\":4},\"feels_like\":{\"day\":12.08,\"night\":0.9,\"eve\":10.87,\"morn\":0.9},\"pressure\":1024,\"humidity\":40,\"dew_point\":0.58,\"wind_speed\":6.09,\"wind_deg\":152,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.11},{\"dt\":1618308000,\"sunrise\":1618283705,\"sunset\":1618333607,\"temp\":{\"day\":14.42,\"min\":4.45,\"max\":16.91,\"night\":11.72,\"eve\":16.64,\"morn\":4.45},\"feels_like\":{\"day\":13.17,\"night\":2.28,\"eve\":15.43,\"morn\":2.28},\"pressure\":1019,\"humidity\":48,\"dew_point\":3.67,\"wind_speed\":3.07,\"wind_deg\":153,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":8,\"pop\":0,\"uvi\":3.53},{\"dt\":1618394400,\"sunrise\":1618369965,\"sunset\":1618420117,\"temp\":{\"day\":10.12,\"min\":7.84,\"max\":10.7,\"night\":8.87,\"eve\":9.78,\"morn\":7.84},\"feels_like\":{\"day\":9.54,\"night\":6.26,\"eve\":8.02,\"morn\":6.26},\"pressure\":1012,\"humidity\":90,\"dew_point\":8.65,\"wind_speed\":3.6,\"wind_deg\":129,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.98,\"rain\":2.37,\"uvi\":2.7},{\"dt\":1618480800,\"sunrise\":1618456226,\"sunset\":1618506627,\"temp\":{\"day\":8.88,\"min\":6.86,\"max\":10.63,\"night\":8.88,\"eve\":10.63,\"morn\":6.86},\"feels_like\":{\"day\":7.04,\"night\":5.16,\"eve\":9.81,\"morn\":5.16},\"pressure\":1011,\"humidity\":86,\"dew_point\":6.85,\"wind_speed\":3.22,\"wind_deg\":98,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.91,\"rain\":4.23,\"uvi\":3},{\"dt\":1618567200,\"sunrise\":1618542488,\"sunset\":1618593137,\"temp\":{\"day\":5.06,\"min\":4.81,\"max\":8.16,\"night\":4.84,\"eve\":7.24,\"morn\":5.39},\"feels_like\":{\"day\":2.81,\"night\":1.18,\"eve\":6.67,\"morn\":1.18},\"pressure\":1010,\"humidity\":91,\"dew_point\":3.81,\"wind_speed\":2.69,\"wind_deg\":101,\"weather\":[{\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":1,\"rain\":15.37,\"uvi\":3},{\"dt\":1618653600,\"sunrise\":1618628751,\"sunset\":1618679646,\"temp\":{\"day\":3.07,\"min\":1.88,\"max\":5.32,\"night\":1.88,\"eve\":2.04,\"morn\":4.62},\"feels_like\":{\"day\":-0.42,\"night\":1.75,\"eve\":-1.74,\"morn\":1.75},\"pressure\":1010,\"humidity\":97,\"dew_point\":2.74,\"wind_speed\":3.86,\"wind_deg\":287,\"weather\":[{\"id\":616,\"main\":\"Snow\",\"description\":\"rain and snow\",\"icon\":\"13d\"}],\"clouds\":100,\"pop\":1,\"rain\":6.67,\"snow\":8.83,\"uvi\":3}]}"; + final CurrentWeatherData currentWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString); + + assertNotNull(currentWeatherData); + assertNotNull(currentWeatherData.getCurrent()); + assertNull(currentWeatherData.getCurrent().getVisibilityInMetres()); + } + + @Test + public void mapToCurrent_withoutHourlyListNode() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"snow\":{},\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"daily\":[{\"dt\":1618048800,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":{\"day\":11.84,\"min\":1.69,\"max\":13.04,\"night\":7.78,\"eve\":11.02,\"morn\":1.69},\"feels_like\":{\"day\":10.12,\"night\":-2.86,\"eve\":9.72,\"morn\":-2.86},\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"wind_speed\":7.72,\"wind_deg\":200,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.36},{\"dt\":1618135200,\"sunrise\":1618111186,\"sunset\":1618160588,\"temp\":{\"day\":14.03,\"min\":4.51,\"max\":15.81,\"night\":8.07,\"eve\":12.85,\"morn\":4.51},\"feels_like\":{\"day\":12.87,\"night\":1.64,\"eve\":11.73,\"morn\":1.64},\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"wind_speed\":5.11,\"wind_deg\":194,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":100,\"pop\":0,\"uvi\":3.09},{\"dt\":1618221600,\"sunrise\":1618197445,\"sunset\":1618247098,\"temp\":{\"day\":13.62,\"min\":4,\"max\":14.94,\"night\":7.62,\"eve\":12.21,\"morn\":4},\"feels_like\":{\"day\":12.08,\"night\":0.9,\"eve\":10.87,\"morn\":0.9},\"pressure\":1024,\"humidity\":40,\"dew_point\":0.58,\"wind_speed\":6.09,\"wind_deg\":152,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.11},{\"dt\":1618308000,\"sunrise\":1618283705,\"sunset\":1618333607,\"temp\":{\"day\":14.42,\"min\":4.45,\"max\":16.91,\"night\":11.72,\"eve\":16.64,\"morn\":4.45},\"feels_like\":{\"day\":13.17,\"night\":2.28,\"eve\":15.43,\"morn\":2.28},\"pressure\":1019,\"humidity\":48,\"dew_point\":3.67,\"wind_speed\":3.07,\"wind_deg\":153,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":8,\"pop\":0,\"uvi\":3.53},{\"dt\":1618394400,\"sunrise\":1618369965,\"sunset\":1618420117,\"temp\":{\"day\":10.12,\"min\":7.84,\"max\":10.7,\"night\":8.87,\"eve\":9.78,\"morn\":7.84},\"feels_like\":{\"day\":9.54,\"night\":6.26,\"eve\":8.02,\"morn\":6.26},\"pressure\":1012,\"humidity\":90,\"dew_point\":8.65,\"wind_speed\":3.6,\"wind_deg\":129,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.98,\"rain\":2.37,\"uvi\":2.7},{\"dt\":1618480800,\"sunrise\":1618456226,\"sunset\":1618506627,\"temp\":{\"day\":8.88,\"min\":6.86,\"max\":10.63,\"night\":8.88,\"eve\":10.63,\"morn\":6.86},\"feels_like\":{\"day\":7.04,\"night\":5.16,\"eve\":9.81,\"morn\":5.16},\"pressure\":1011,\"humidity\":86,\"dew_point\":6.85,\"wind_speed\":3.22,\"wind_deg\":98,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.91,\"rain\":4.23,\"uvi\":3},{\"dt\":1618567200,\"sunrise\":1618542488,\"sunset\":1618593137,\"temp\":{\"day\":5.06,\"min\":4.81,\"max\":8.16,\"night\":4.84,\"eve\":7.24,\"morn\":5.39},\"feels_like\":{\"day\":2.81,\"night\":1.18,\"eve\":6.67,\"morn\":1.18},\"pressure\":1010,\"humidity\":91,\"dew_point\":3.81,\"wind_speed\":2.69,\"wind_deg\":101,\"weather\":[{\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":1,\"rain\":15.37,\"uvi\":3},{\"dt\":1618653600,\"sunrise\":1618628751,\"sunset\":1618679646,\"temp\":{\"day\":3.07,\"min\":1.88,\"max\":5.32,\"night\":1.88,\"eve\":2.04,\"morn\":4.62},\"feels_like\":{\"day\":-0.42,\"night\":1.75,\"eve\":-1.74,\"morn\":1.75},\"pressure\":1010,\"humidity\":97,\"dew_point\":2.74,\"wind_speed\":3.86,\"wind_deg\":287,\"weather\":[{\"id\":616,\"main\":\"Snow\",\"description\":\"rain and snow\",\"icon\":\"13d\"}],\"clouds\":100,\"pop\":1,\"rain\":6.67,\"snow\":8.83,\"uvi\":3}]}"; + final CurrentWeatherData currentWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString); + + assertNotNull(currentWeatherData); + assertNull(currentWeatherData.getHourlyList()); + } + + @Test + public void mapToCurrent_withHourlyVariations() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"rain\":{},\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"hourly\":[{\"dt\":1618048800,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"clouds\":0,\"wind_speed\":7.72,\"wind_deg\":200,\"wind_gust\":10.55,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},{\"dt\":1618052400,\"temp\":11.6,\"feels_like\":9.96,\"pressure\":1018,\"humidity\":44,\"dew_point\":-0.2,\"uvi\":3.22,\"clouds\":32,\"visibility\":10000,\"wind_speed\":7.76,\"wind_deg\":202,\"wind_gust\":10.75,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618056000,\"temp\":12.26,\"feels_like\":10.72,\"pressure\":1018,\"humidity\":45,\"dew_point\":0.68,\"uvi\":2.67,\"clouds\":49,\"visibility\":10000,\"wind_speed\":7.66,\"wind_deg\":205,\"wind_gust\":10.76,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618059600,\"temp\":12.86,\"feels_like\":11.4,\"pressure\":1018,\"humidity\":46,\"dew_point\":1.53,\"uvi\":1.22,\"clouds\":19,\"visibility\":10000,\"wind_speed\":7.15,\"wind_deg\":210,\"wind_gust\":9.99,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618063200,\"temp\":13.04,\"feels_like\":11.68,\"pressure\":1018,\"humidity\":49,\"dew_point\":2.58,\"uvi\":0.7,\"clouds\":50,\"visibility\":10000,\"wind_speed\":5.95,\"wind_deg\":210,\"wind_gust\":9.4,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618066800,\"temp\":12.53,\"feels_like\":11.2,\"pressure\":1018,\"humidity\":52,\"dew_point\":3.07,\"uvi\":0.32,\"clouds\":48,\"visibility\":10000,\"wind_speed\":5.43,\"wind_deg\":209,\"wind_gust\":9.32,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618070400,\"temp\":11.02,\"feels_like\":9.72,\"pressure\":1018,\"humidity\":59,\"dew_point\":3.37,\"uvi\":0.12,\"clouds\":51,\"visibility\":10000,\"wind_speed\":4.22,\"wind_deg\":200,\"wind_gust\":8.94,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618074000,\"temp\":8.81,\"feels_like\":6.7,\"pressure\":1019,\"humidity\":67,\"dew_point\":3.23,\"uvi\":0,\"clouds\":55,\"visibility\":10000,\"wind_speed\":3.67,\"wind_deg\":184,\"wind_gust\":8.41,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618077600,\"temp\":7.94,\"feels_like\":5.47,\"pressure\":1020,\"humidity\":71,\"dew_point\":3.06,\"uvi\":0,\"clouds\":59,\"visibility\":10000,\"wind_speed\":4,\"wind_deg\":177,\"wind_gust\":10.47,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618081200,\"temp\":7.68,\"feels_like\":4.81,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.92,\"uvi\":0,\"clouds\":79,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":179,\"wind_gust\":12.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618084800,\"temp\":7.78,\"feels_like\":4.76,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.89,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":5.12,\"wind_deg\":185,\"wind_gust\":13.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618088400,\"temp\":7.45,\"feels_like\":4.33,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.77,\"uvi\":0,\"clouds\":86,\"visibility\":10000,\"wind_speed\":5.17,\"wind_deg\":190,\"wind_gust\":13.37,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618092000,\"temp\":6.97,\"feels_like\":3.85,\"pressure\":1021,\"humidity\":74,\"dew_point\":2.67,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":4.89,\"wind_deg\":192,\"wind_gust\":12.68,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618095600,\"temp\":6.46,\"feels_like\":3.4,\"pressure\":1021,\"humidity\":76,\"dew_point\":2.7,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":191,\"wind_gust\":11.89,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618099200,\"temp\":5.96,\"feels_like\":2.9,\"pressure\":1021,\"humidity\":79,\"dew_point\":2.65,\"uvi\":0,\"clouds\":91,\"visibility\":10000,\"wind_speed\":4.26,\"wind_deg\":188,\"wind_gust\":11.23,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618102800,\"temp\":5.31,\"feels_like\":2.22,\"pressure\":1022,\"humidity\":81,\"dew_point\":2.47,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.04,\"wind_deg\":186,\"wind_gust\":10.72,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618106400,\"temp\":5.2,\"feels_like\":2.18,\"pressure\":1022,\"humidity\":82,\"dew_point\":2.41,\"uvi\":0,\"clouds\":95,\"visibility\":10000,\"wind_speed\":3.87,\"wind_deg\":190,\"wind_gust\":10.92,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618110000,\"temp\":4.56,\"feels_like\":1.51,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.29,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":3.69,\"wind_deg\":186,\"wind_gust\":10.33,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618113600,\"temp\":4.51,\"feels_like\":1.64,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.33,\"uvi\":0,\"clouds\":84,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":191,\"wind_gust\":10.18,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618117200,\"temp\":6.05,\"feels_like\":3.41,\"pressure\":1024,\"humidity\":80,\"dew_point\":2.89,\"uvi\":0.15,\"clouds\":80,\"visibility\":10000,\"wind_speed\":3.55,\"wind_deg\":193,\"wind_gust\":10.09,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618120800,\"temp\":7.96,\"feels_like\":5.31,\"pressure\":1024,\"humidity\":72,\"dew_point\":3.29,\"uvi\":0.38,\"clouds\":80,\"visibility\":10000,\"wind_speed\":4.39,\"wind_deg\":197,\"wind_gust\":8.53,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618124400,\"temp\":9.61,\"feels_like\":7.3,\"pressure\":1024,\"humidity\":67,\"dew_point\":3.88,\"uvi\":1.01,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":197,\"wind_gust\":7.77,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618128000,\"temp\":11.14,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":62,\"dew_point\":4.27,\"uvi\":1.54,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":198,\"wind_gust\":7.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618131600,\"temp\":12.8,\"feels_like\":11.62,\"pressure\":1025,\"humidity\":57,\"dew_point\":4.57,\"uvi\":1.97,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.87,\"wind_deg\":196,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618135200,\"temp\":14.03,\"feels_like\":12.87,\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"uvi\":3.09,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.11,\"wind_deg\":194,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618138800,\"temp\":14.82,\"feels_like\":13.66,\"pressure\":1025,\"humidity\":50,\"dew_point\":4.62,\"uvi\":2.96,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.32,\"wind_deg\":191,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618142400,\"temp\":15.64,\"feels_like\":14.49,\"pressure\":1025,\"humidity\":47,\"dew_point\":4.48,\"uvi\":2.45,\"clouds\":94,\"visibility\":10000,\"wind_speed\":5.42,\"wind_deg\":192,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618146000,\"temp\":15.81,\"feels_like\":14.62,\"pressure\":1024,\"humidity\":45,\"dew_point\":4.15,\"uvi\":2.02,\"clouds\":24,\"visibility\":10000,\"wind_speed\":5.15,\"wind_deg\":193,\"wind_gust\":6.3,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618149600,\"temp\":15.71,\"feels_like\":14.51,\"pressure\":1025,\"humidity\":45,\"dew_point\":3.87,\"uvi\":1.17,\"clouds\":48,\"visibility\":10000,\"wind_speed\":4.79,\"wind_deg\":188,\"wind_gust\":6.01,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618153200,\"temp\":14.79,\"feels_like\":13.63,\"pressure\":1024,\"humidity\":50,\"dew_point\":4.71,\"uvi\":0.53,\"clouds\":63,\"visibility\":10000,\"wind_speed\":3.73,\"wind_deg\":177,\"wind_gust\":6.35,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618156800,\"temp\":12.85,\"feels_like\":11.73,\"pressure\":1024,\"humidity\":59,\"dew_point\":5.18,\"uvi\":0.17,\"clouds\":72,\"visibility\":10000,\"wind_speed\":3.05,\"wind_deg\":159,\"wind_gust\":6.38,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618160400,\"temp\":10.92,\"feels_like\":9.71,\"pressure\":1025,\"humidity\":63,\"dew_point\":4.26,\"uvi\":0,\"clouds\":78,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":152,\"wind_gust\":6.64,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618164000,\"temp\":9.65,\"feels_like\":7.72,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.66,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":3.68,\"wind_deg\":148,\"wind_gust\":9.04,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618167600,\"temp\":8.82,\"feels_like\":6.59,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.05,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.92,\"wind_deg\":147,\"wind_gust\":11.02,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618171200,\"temp\":8.07,\"feels_like\":5.87,\"pressure\":1026,\"humidity\":67,\"dew_point\":2.43,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.54,\"wind_deg\":154,\"wind_gust\":11.12,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618174800,\"temp\":7.24,\"feels_like\":4.99,\"pressure\":1027,\"humidity\":68,\"dew_point\":1.96,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.32,\"wind_deg\":154,\"wind_gust\":10.55,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618178400,\"temp\":6.58,\"feels_like\":4.31,\"pressure\":1027,\"humidity\":70,\"dew_point\":1.65,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.14,\"wind_deg\":154,\"wind_gust\":9.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618182000,\"temp\":6.03,\"feels_like\":3.57,\"pressure\":1027,\"humidity\":71,\"dew_point\":1.26,\"uvi\":0,\"clouds\":82,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":150,\"wind_gust\":8.44,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618185600,\"temp\":5.51,\"feels_like\":2.94,\"pressure\":1027,\"humidity\":72,\"dew_point\":0.95,\"uvi\":0,\"clouds\":71,\"visibility\":10000,\"wind_speed\":3.26,\"wind_deg\":150,\"wind_gust\":8.58,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618189200,\"temp\":5,\"feels_like\":2.29,\"pressure\":1027,\"humidity\":74,\"dew_point\":0.72,\"uvi\":0,\"clouds\":9,\"visibility\":10000,\"wind_speed\":3.3,\"wind_deg\":147,\"wind_gust\":8.63,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"pop\":0},{\"dt\":1618192800,\"temp\":4.47,\"feels_like\":1.69,\"pressure\":1027,\"humidity\":75,\"dew_point\":0.52,\"uvi\":0,\"clouds\":14,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":145,\"wind_gust\":8.14,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618196400,\"temp\":4.03,\"feels_like\":1.08,\"pressure\":1026,\"humidity\":76,\"dew_point\":0.22,\"uvi\":0,\"clouds\":12,\"visibility\":10000,\"wind_speed\":3.36,\"wind_deg\":138,\"wind_gust\":8.13,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618200000,\"temp\":4,\"feels_like\":0.9,\"pressure\":1026,\"humidity\":75,\"dew_point\":0.13,\"uvi\":0.08,\"clouds\":10,\"visibility\":10000,\"wind_speed\":3.57,\"wind_deg\":131,\"wind_gust\":9.24,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618203600,\"temp\":5.73,\"feels_like\":2.73,\"pressure\":1026,\"humidity\":68,\"dew_point\":0.52,\"uvi\":0.33,\"clouds\":8,\"visibility\":10000,\"wind_speed\":4.05,\"wind_deg\":138,\"wind_gust\":10.36,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618207200,\"temp\":7.87,\"feels_like\":4.9,\"pressure\":1025,\"humidity\":59,\"dew_point\":0.53,\"uvi\":0.84,\"clouds\":7,\"visibility\":10000,\"wind_speed\":5.05,\"wind_deg\":145,\"wind_gust\":10.48,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618210800,\"temp\":9.9,\"feels_like\":7.29,\"pressure\":1025,\"humidity\":53,\"dew_point\":0.8,\"uvi\":1.56,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.48,\"wind_deg\":147,\"wind_gust\":9.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618214400,\"temp\":11.5,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":47,\"dew_point\":0.86,\"uvi\":2.37,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.94,\"wind_deg\":152,\"wind_gust\":8.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618218000,\"temp\":12.64,\"feels_like\":11.08,\"pressure\":1024,\"humidity\":43,\"dew_point\":0.68,\"uvi\":3.04,\"clouds\":0,\"visibility\":10000,\"wind_speed\":6.25,\"wind_deg\":151,\"wind_gust\":8.5,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0}],\"daily\":[{\"dt\":1618048800,\"sunrise\":1618024927,\"sunset\":1618074079,\"temp\":{\"day\":11.84,\"min\":1.69,\"max\":13.04,\"night\":7.78,\"eve\":11.02,\"morn\":1.69},\"feels_like\":{\"day\":10.12,\"night\":-2.86,\"eve\":9.72,\"morn\":-2.86},\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"wind_speed\":7.72,\"wind_deg\":200,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.36},{\"dt\":1618135200,\"sunrise\":1618111186,\"sunset\":1618160588,\"temp\":{\"day\":14.03,\"min\":4.51,\"max\":15.81,\"night\":8.07,\"eve\":12.85,\"morn\":4.51},\"feels_like\":{\"day\":12.87,\"night\":1.64,\"eve\":11.73,\"morn\":1.64},\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"wind_speed\":5.11,\"wind_deg\":194,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"clouds\":100,\"pop\":0,\"uvi\":3.09},{\"dt\":1618221600,\"sunrise\":1618197445,\"sunset\":1618247098,\"temp\":{\"day\":13.62,\"min\":4,\"max\":14.94,\"night\":7.62,\"eve\":12.21,\"morn\":4},\"feels_like\":{\"day\":12.08,\"night\":0.9,\"eve\":10.87,\"morn\":0.9},\"pressure\":1024,\"humidity\":40,\"dew_point\":0.58,\"wind_speed\":6.09,\"wind_deg\":152,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":0,\"pop\":0,\"uvi\":3.11},{\"dt\":1618308000,\"sunrise\":1618283705,\"sunset\":1618333607,\"temp\":{\"day\":14.42,\"min\":4.45,\"max\":16.91,\"night\":11.72,\"eve\":16.64,\"morn\":4.45},\"feels_like\":{\"day\":13.17,\"night\":2.28,\"eve\":15.43,\"morn\":2.28},\"pressure\":1019,\"humidity\":48,\"dew_point\":3.67,\"wind_speed\":3.07,\"wind_deg\":153,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"clouds\":8,\"pop\":0,\"uvi\":3.53},{\"dt\":1618394400,\"sunrise\":1618369965,\"sunset\":1618420117,\"temp\":{\"day\":10.12,\"min\":7.84,\"max\":10.7,\"night\":8.87,\"eve\":9.78,\"morn\":7.84},\"feels_like\":{\"day\":9.54,\"night\":6.26,\"eve\":8.02,\"morn\":6.26},\"pressure\":1012,\"humidity\":90,\"dew_point\":8.65,\"wind_speed\":3.6,\"wind_deg\":129,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.98,\"rain\":2.37,\"uvi\":2.7},{\"dt\":1618480800,\"sunrise\":1618456226,\"sunset\":1618506627,\"temp\":{\"day\":8.88,\"min\":6.86,\"max\":10.63,\"night\":8.88,\"eve\":10.63,\"morn\":6.86},\"feels_like\":{\"day\":7.04,\"night\":5.16,\"eve\":9.81,\"morn\":5.16},\"pressure\":1011,\"humidity\":86,\"dew_point\":6.85,\"wind_speed\":3.22,\"wind_deg\":98,\"weather\":[{\"id\":500,\"main\":\"Rain\",\"description\":\"light rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":0.91,\"rain\":4.23,\"uvi\":3},{\"dt\":1618567200,\"sunrise\":1618542488,\"sunset\":1618593137,\"temp\":{\"day\":5.06,\"min\":4.81,\"max\":8.16,\"night\":4.84,\"eve\":7.24,\"morn\":5.39},\"feels_like\":{\"day\":2.81,\"night\":1.18,\"eve\":6.67,\"morn\":1.18},\"pressure\":1010,\"humidity\":91,\"dew_point\":3.81,\"wind_speed\":2.69,\"wind_deg\":101,\"weather\":[{\"id\":501,\"main\":\"Rain\",\"description\":\"moderate rain\",\"icon\":\"10d\"}],\"clouds\":100,\"pop\":1,\"rain\":15.37,\"uvi\":3},{\"dt\":1618653600,\"sunrise\":1618628751,\"sunset\":1618679646,\"temp\":{\"day\":3.07,\"min\":1.88,\"max\":5.32,\"night\":1.88,\"eve\":2.04,\"morn\":4.62},\"feels_like\":{\"day\":-0.42,\"night\":1.75,\"eve\":-1.74,\"morn\":1.75},\"pressure\":1010,\"humidity\":97,\"dew_point\":2.74,\"wind_speed\":3.86,\"wind_deg\":287,\"weather\":[{\"id\":616,\"main\":\"Snow\",\"description\":\"rain and snow\",\"icon\":\"13d\"}],\"clouds\":100,\"pop\":1,\"rain\":6.67,\"snow\":8.83,\"uvi\":3}]}"; + final CurrentWeatherData currentWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString); + + assertNotNull(currentWeatherData); + assertNull(currentWeatherData.getHourlyList().get(0).getUvIndex()); + assertNull(currentWeatherData.getHourlyList().get(0).getVisibilityInMetres()); + assertNull(currentWeatherData.getHourlyList().get(0).getProbabilityOfPrecipitation()); + } + + @Test + public void mapToCurrent_withoutDailyListNode() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"snow\":{\"1h\":20},\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"minutely\":[{\"dt\":1618050060,\"precipitation\":0},{\"dt\":1618050120,\"precipitation\":0},{\"dt\":1618050180,\"precipitation\":0},{\"dt\":1618050240,\"precipitation\":0},{\"dt\":1618050300,\"precipitation\":0},{\"dt\":1618050360,\"precipitation\":0},{\"dt\":1618050420,\"precipitation\":0},{\"dt\":1618050480,\"precipitation\":0},{\"dt\":1618050540,\"precipitation\":0},{\"dt\":1618050600,\"precipitation\":0},{\"dt\":1618050660,\"precipitation\":0},{\"dt\":1618050720,\"precipitation\":0},{\"dt\":1618050780,\"precipitation\":0},{\"dt\":1618050840,\"precipitation\":0},{\"dt\":1618050900,\"precipitation\":0},{\"dt\":1618050960,\"precipitation\":0},{\"dt\":1618051020,\"precipitation\":0},{\"dt\":1618051080,\"precipitation\":0},{\"dt\":1618051140,\"precipitation\":0},{\"dt\":1618051200,\"precipitation\":0},{\"dt\":1618051260,\"precipitation\":0},{\"dt\":1618051320,\"precipitation\":0},{\"dt\":1618051380,\"precipitation\":0},{\"dt\":1618051440,\"precipitation\":0},{\"dt\":1618051500,\"precipitation\":0},{\"dt\":1618051560,\"precipitation\":0},{\"dt\":1618051620,\"precipitation\":0},{\"dt\":1618051680,\"precipitation\":0},{\"dt\":1618051740,\"precipitation\":0},{\"dt\":1618051800,\"precipitation\":0},{\"dt\":1618051860,\"precipitation\":0},{\"dt\":1618051920,\"precipitation\":0},{\"dt\":1618051980,\"precipitation\":0},{\"dt\":1618052040,\"precipitation\":0},{\"dt\":1618052100,\"precipitation\":0},{\"dt\":1618052160,\"precipitation\":0},{\"dt\":1618052220,\"precipitation\":0},{\"dt\":1618052280,\"precipitation\":0},{\"dt\":1618052340,\"precipitation\":0},{\"dt\":1618052400,\"precipitation\":0},{\"dt\":1618052460,\"precipitation\":0},{\"dt\":1618052520,\"precipitation\":0},{\"dt\":1618052580,\"precipitation\":0},{\"dt\":1618052640,\"precipitation\":0},{\"dt\":1618052700,\"precipitation\":0},{\"dt\":1618052760,\"precipitation\":0},{\"dt\":1618052820,\"precipitation\":0},{\"dt\":1618052880,\"precipitation\":0},{\"dt\":1618052940,\"precipitation\":0},{\"dt\":1618053000,\"precipitation\":0},{\"dt\":1618053060,\"precipitation\":0},{\"dt\":1618053120,\"precipitation\":0},{\"dt\":1618053180,\"precipitation\":0},{\"dt\":1618053240,\"precipitation\":0},{\"dt\":1618053300,\"precipitation\":0},{\"dt\":1618053360,\"precipitation\":0},{\"dt\":1618053420,\"precipitation\":0},{\"dt\":1618053480,\"precipitation\":0},{\"dt\":1618053540,\"precipitation\":0},{\"dt\":1618053600,\"precipitation\":0},{\"dt\":1618053660,\"precipitation\":0}],\"hourly\":[{\"dt\":1618048800,\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":7.72,\"wind_deg\":200,\"wind_gust\":10.55,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618052400,\"temp\":11.6,\"feels_like\":9.96,\"pressure\":1018,\"humidity\":44,\"dew_point\":-0.2,\"uvi\":3.22,\"clouds\":32,\"visibility\":10000,\"wind_speed\":7.76,\"wind_deg\":202,\"wind_gust\":10.75,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618056000,\"temp\":12.26,\"feels_like\":10.72,\"pressure\":1018,\"humidity\":45,\"dew_point\":0.68,\"uvi\":2.67,\"clouds\":49,\"visibility\":10000,\"wind_speed\":7.66,\"wind_deg\":205,\"wind_gust\":10.76,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618059600,\"temp\":12.86,\"feels_like\":11.4,\"pressure\":1018,\"humidity\":46,\"dew_point\":1.53,\"uvi\":1.22,\"clouds\":19,\"visibility\":10000,\"wind_speed\":7.15,\"wind_deg\":210,\"wind_gust\":9.99,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618063200,\"temp\":13.04,\"feels_like\":11.68,\"pressure\":1018,\"humidity\":49,\"dew_point\":2.58,\"uvi\":0.7,\"clouds\":50,\"visibility\":10000,\"wind_speed\":5.95,\"wind_deg\":210,\"wind_gust\":9.4,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618066800,\"temp\":12.53,\"feels_like\":11.2,\"pressure\":1018,\"humidity\":52,\"dew_point\":3.07,\"uvi\":0.32,\"clouds\":48,\"visibility\":10000,\"wind_speed\":5.43,\"wind_deg\":209,\"wind_gust\":9.32,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618070400,\"temp\":11.02,\"feels_like\":9.72,\"pressure\":1018,\"humidity\":59,\"dew_point\":3.37,\"uvi\":0.12,\"clouds\":51,\"visibility\":10000,\"wind_speed\":4.22,\"wind_deg\":200,\"wind_gust\":8.94,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618074000,\"temp\":8.81,\"feels_like\":6.7,\"pressure\":1019,\"humidity\":67,\"dew_point\":3.23,\"uvi\":0,\"clouds\":55,\"visibility\":10000,\"wind_speed\":3.67,\"wind_deg\":184,\"wind_gust\":8.41,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618077600,\"temp\":7.94,\"feels_like\":5.47,\"pressure\":1020,\"humidity\":71,\"dew_point\":3.06,\"uvi\":0,\"clouds\":59,\"visibility\":10000,\"wind_speed\":4,\"wind_deg\":177,\"wind_gust\":10.47,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618081200,\"temp\":7.68,\"feels_like\":4.81,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.92,\"uvi\":0,\"clouds\":79,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":179,\"wind_gust\":12.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618084800,\"temp\":7.78,\"feels_like\":4.76,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.89,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":5.12,\"wind_deg\":185,\"wind_gust\":13.11,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618088400,\"temp\":7.45,\"feels_like\":4.33,\"pressure\":1020,\"humidity\":71,\"dew_point\":2.77,\"uvi\":0,\"clouds\":86,\"visibility\":10000,\"wind_speed\":5.17,\"wind_deg\":190,\"wind_gust\":13.37,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618092000,\"temp\":6.97,\"feels_like\":3.85,\"pressure\":1021,\"humidity\":74,\"dew_point\":2.67,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":4.89,\"wind_deg\":192,\"wind_gust\":12.68,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618095600,\"temp\":6.46,\"feels_like\":3.4,\"pressure\":1021,\"humidity\":76,\"dew_point\":2.7,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":191,\"wind_gust\":11.89,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618099200,\"temp\":5.96,\"feels_like\":2.9,\"pressure\":1021,\"humidity\":79,\"dew_point\":2.65,\"uvi\":0,\"clouds\":91,\"visibility\":10000,\"wind_speed\":4.26,\"wind_deg\":188,\"wind_gust\":11.23,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618102800,\"temp\":5.31,\"feels_like\":2.22,\"pressure\":1022,\"humidity\":81,\"dew_point\":2.47,\"uvi\":0,\"clouds\":89,\"visibility\":10000,\"wind_speed\":4.04,\"wind_deg\":186,\"wind_gust\":10.72,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618106400,\"temp\":5.2,\"feels_like\":2.18,\"pressure\":1022,\"humidity\":82,\"dew_point\":2.41,\"uvi\":0,\"clouds\":95,\"visibility\":10000,\"wind_speed\":3.87,\"wind_deg\":190,\"wind_gust\":10.92,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618110000,\"temp\":4.56,\"feels_like\":1.51,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.29,\"uvi\":0,\"clouds\":88,\"visibility\":10000,\"wind_speed\":3.69,\"wind_deg\":186,\"wind_gust\":10.33,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618113600,\"temp\":4.51,\"feels_like\":1.64,\"pressure\":1023,\"humidity\":85,\"dew_point\":2.33,\"uvi\":0,\"clouds\":84,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":191,\"wind_gust\":10.18,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618117200,\"temp\":6.05,\"feels_like\":3.41,\"pressure\":1024,\"humidity\":80,\"dew_point\":2.89,\"uvi\":0.15,\"clouds\":80,\"visibility\":10000,\"wind_speed\":3.55,\"wind_deg\":193,\"wind_gust\":10.09,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618120800,\"temp\":7.96,\"feels_like\":5.31,\"pressure\":1024,\"humidity\":72,\"dew_point\":3.29,\"uvi\":0.38,\"clouds\":80,\"visibility\":10000,\"wind_speed\":4.39,\"wind_deg\":197,\"wind_gust\":8.53,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618124400,\"temp\":9.61,\"feels_like\":7.3,\"pressure\":1024,\"humidity\":67,\"dew_point\":3.88,\"uvi\":1.01,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.5,\"wind_deg\":197,\"wind_gust\":7.77,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618128000,\"temp\":11.14,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":62,\"dew_point\":4.27,\"uvi\":1.54,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.71,\"wind_deg\":198,\"wind_gust\":7.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618131600,\"temp\":12.8,\"feels_like\":11.62,\"pressure\":1025,\"humidity\":57,\"dew_point\":4.57,\"uvi\":1.97,\"clouds\":100,\"visibility\":10000,\"wind_speed\":4.87,\"wind_deg\":196,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618135200,\"temp\":14.03,\"feels_like\":12.87,\"pressure\":1025,\"humidity\":53,\"dew_point\":4.65,\"uvi\":3.09,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.11,\"wind_deg\":194,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618138800,\"temp\":14.82,\"feels_like\":13.66,\"pressure\":1025,\"humidity\":50,\"dew_point\":4.62,\"uvi\":2.96,\"clouds\":100,\"visibility\":10000,\"wind_speed\":5.32,\"wind_deg\":191,\"wind_gust\":6.82,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618142400,\"temp\":15.64,\"feels_like\":14.49,\"pressure\":1025,\"humidity\":47,\"dew_point\":4.48,\"uvi\":2.45,\"clouds\":94,\"visibility\":10000,\"wind_speed\":5.42,\"wind_deg\":192,\"wind_gust\":6.7,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618146000,\"temp\":15.81,\"feels_like\":14.62,\"pressure\":1024,\"humidity\":45,\"dew_point\":4.15,\"uvi\":2.02,\"clouds\":24,\"visibility\":10000,\"wind_speed\":5.15,\"wind_deg\":193,\"wind_gust\":6.3,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02d\"}],\"pop\":0},{\"dt\":1618149600,\"temp\":15.71,\"feels_like\":14.51,\"pressure\":1025,\"humidity\":45,\"dew_point\":3.87,\"uvi\":1.17,\"clouds\":48,\"visibility\":10000,\"wind_speed\":4.79,\"wind_deg\":188,\"wind_gust\":6.01,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}],\"pop\":0},{\"dt\":1618153200,\"temp\":14.79,\"feels_like\":13.63,\"pressure\":1024,\"humidity\":50,\"dew_point\":4.71,\"uvi\":0.53,\"clouds\":63,\"visibility\":10000,\"wind_speed\":3.73,\"wind_deg\":177,\"wind_gust\":6.35,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618156800,\"temp\":12.85,\"feels_like\":11.73,\"pressure\":1024,\"humidity\":59,\"dew_point\":5.18,\"uvi\":0.17,\"clouds\":72,\"visibility\":10000,\"wind_speed\":3.05,\"wind_deg\":159,\"wind_gust\":6.38,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618160400,\"temp\":10.92,\"feels_like\":9.71,\"pressure\":1025,\"humidity\":63,\"dew_point\":4.26,\"uvi\":0,\"clouds\":78,\"visibility\":10000,\"wind_speed\":3.39,\"wind_deg\":152,\"wind_gust\":6.64,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}],\"pop\":0},{\"dt\":1618164000,\"temp\":9.65,\"feels_like\":7.72,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.66,\"uvi\":0,\"clouds\":81,\"visibility\":10000,\"wind_speed\":3.68,\"wind_deg\":148,\"wind_gust\":9.04,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618167600,\"temp\":8.82,\"feels_like\":6.59,\"pressure\":1026,\"humidity\":66,\"dew_point\":3.05,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.92,\"wind_deg\":147,\"wind_gust\":11.02,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618171200,\"temp\":8.07,\"feels_like\":5.87,\"pressure\":1026,\"humidity\":67,\"dew_point\":2.43,\"uvi\":0,\"clouds\":100,\"visibility\":10000,\"wind_speed\":3.54,\"wind_deg\":154,\"wind_gust\":11.12,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618174800,\"temp\":7.24,\"feels_like\":4.99,\"pressure\":1027,\"humidity\":68,\"dew_point\":1.96,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.32,\"wind_deg\":154,\"wind_gust\":10.55,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618178400,\"temp\":6.58,\"feels_like\":4.31,\"pressure\":1027,\"humidity\":70,\"dew_point\":1.65,\"uvi\":0,\"clouds\":98,\"visibility\":10000,\"wind_speed\":3.14,\"wind_deg\":154,\"wind_gust\":9.19,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618182000,\"temp\":6.03,\"feels_like\":3.57,\"pressure\":1027,\"humidity\":71,\"dew_point\":1.26,\"uvi\":0,\"clouds\":82,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":150,\"wind_gust\":8.44,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618185600,\"temp\":5.51,\"feels_like\":2.94,\"pressure\":1027,\"humidity\":72,\"dew_point\":0.95,\"uvi\":0,\"clouds\":71,\"visibility\":10000,\"wind_speed\":3.26,\"wind_deg\":150,\"wind_gust\":8.58,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}],\"pop\":0},{\"dt\":1618189200,\"temp\":5,\"feels_like\":2.29,\"pressure\":1027,\"humidity\":74,\"dew_point\":0.72,\"uvi\":0,\"clouds\":9,\"visibility\":10000,\"wind_speed\":3.3,\"wind_deg\":147,\"wind_gust\":8.63,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01n\"}],\"pop\":0},{\"dt\":1618192800,\"temp\":4.47,\"feels_like\":1.69,\"pressure\":1027,\"humidity\":75,\"dew_point\":0.52,\"uvi\":0,\"clouds\":14,\"visibility\":10000,\"wind_speed\":3.25,\"wind_deg\":145,\"wind_gust\":8.14,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618196400,\"temp\":4.03,\"feels_like\":1.08,\"pressure\":1026,\"humidity\":76,\"dew_point\":0.22,\"uvi\":0,\"clouds\":12,\"visibility\":10000,\"wind_speed\":3.36,\"wind_deg\":138,\"wind_gust\":8.13,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}],\"pop\":0},{\"dt\":1618200000,\"temp\":4,\"feels_like\":0.9,\"pressure\":1026,\"humidity\":75,\"dew_point\":0.13,\"uvi\":0.08,\"clouds\":10,\"visibility\":10000,\"wind_speed\":3.57,\"wind_deg\":131,\"wind_gust\":9.24,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618203600,\"temp\":5.73,\"feels_like\":2.73,\"pressure\":1026,\"humidity\":68,\"dew_point\":0.52,\"uvi\":0.33,\"clouds\":8,\"visibility\":10000,\"wind_speed\":4.05,\"wind_deg\":138,\"wind_gust\":10.36,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618207200,\"temp\":7.87,\"feels_like\":4.9,\"pressure\":1025,\"humidity\":59,\"dew_point\":0.53,\"uvi\":0.84,\"clouds\":7,\"visibility\":10000,\"wind_speed\":5.05,\"wind_deg\":145,\"wind_gust\":10.48,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618210800,\"temp\":9.9,\"feels_like\":7.29,\"pressure\":1025,\"humidity\":53,\"dew_point\":0.8,\"uvi\":1.56,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.48,\"wind_deg\":147,\"wind_gust\":9.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618214400,\"temp\":11.5,\"feels_like\":9.93,\"pressure\":1025,\"humidity\":47,\"dew_point\":0.86,\"uvi\":2.37,\"clouds\":0,\"visibility\":10000,\"wind_speed\":5.94,\"wind_deg\":152,\"wind_gust\":8.78,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0},{\"dt\":1618218000,\"temp\":12.64,\"feels_like\":11.08,\"pressure\":1024,\"humidity\":43,\"dew_point\":0.68,\"uvi\":3.04,\"clouds\":0,\"visibility\":10000,\"wind_speed\":6.25,\"wind_deg\":151,\"wind_gust\":8.5,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}],\"pop\":0}]}"; + final CurrentWeatherData currentWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString); + + assertNotNull(currentWeatherData); + assertNull(currentWeatherData.getDailyList()); + } + + @Test + public void mapToCurrent_onlyAlerts() { + final String jsonString = "{\"lat\":53.54,\"lon\":27.34,\"timezone\":\"Europe/Minsk\",\"timezone_offset\":10800,\"current\":{\"dt\":1618050045,\"sunrise\":1618024927,\"sunset\":1618074079,\"rain\":{\"1h\":20},\"temp\":11.84,\"feels_like\":10.12,\"pressure\":1018,\"humidity\":40,\"dew_point\":-1.16,\"uvi\":3.36,\"clouds\":0,\"visibility\":10000,\"wind_speed\":9,\"wind_deg\":200,\"wind_gust\":12,\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"clear sky\",\"icon\":\"01d\"}]},\"alerts\":[{\"sender_name\":\"Sender\",\"event\":\"Event\",\"start\":0,\"end\":400,\"description\":\"Description\"}]}"; + final CurrentWeatherData currentWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToCurrent(jsonString); + + assertNotNull(currentWeatherData); + assertNotNull(currentWeatherData.getAlerts()); + } + + @Test + public void mapToHistorical() { + final String jsonString = "{\"lat\":60.99,\"lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"current\":{\"dt\":1617739371,\"sunrise\":1617678248,\"sunset\":1617727984,\"snow\":{\"1h\":20},\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"uvi\":1.69,\"clouds\":33,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},\"hourly\":[{\"dt\":1617667200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617670800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617674400,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617678000,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617681600,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617685200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617688800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617692400,\"temp\":0.49,\"feels_like\":-7.81,\"pressure\":988,\"humidity\":76,\"dew_point\":-2.87,\"clouds\":100,\"wind_speed\":8.41,\"wind_deg\":196,\"wind_gust\":10.8,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617696000,\"temp\":0.74,\"feels_like\":-7.87,\"pressure\":988,\"humidity\":74,\"dew_point\":-2.97,\"clouds\":100,\"wind_speed\":8.83,\"wind_deg\":196,\"wind_gust\":11.38,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617699600,\"temp\":0.98,\"feels_like\":-7.65,\"pressure\":989,\"humidity\":69,\"dew_point\":-3.59,\"clouds\":99,\"wind_speed\":8.75,\"wind_deg\":203,\"wind_gust\":11.54,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617703200,\"temp\":1.18,\"feels_like\":-7.24,\"pressure\":989,\"humidity\":67,\"dew_point\":-3.77,\"clouds\":86,\"wind_speed\":8.41,\"wind_deg\":205,\"wind_gust\":11.41,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617706800,\"temp\":1.39,\"feels_like\":-6.84,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.77,\"clouds\":77,\"wind_speed\":8.15,\"wind_deg\":199,\"wind_gust\":10.92,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617710400,\"temp\":1.53,\"feels_like\":-6.93,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.65,\"clouds\":42,\"wind_speed\":8.49,\"wind_deg\":191,\"wind_gust\":11.93,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617714000,\"temp\":1.76,\"feels_like\":-7.16,\"pressure\":991,\"humidity\":66,\"dew_point\":-3.46,\"clouds\":47,\"wind_speed\":9.19,\"wind_deg\":199,\"wind_gust\":13.07,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617717600,\"temp\":1.64,\"feels_like\":-7.85,\"pressure\":991,\"humidity\":72,\"dew_point\":-2.53,\"clouds\":67,\"wind_speed\":10.18,\"wind_deg\":205,\"wind_gust\":13.98,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617721200,\"temp\":1.49,\"feels_like\":-7.59,\"pressure\":991,\"humidity\":76,\"dew_point\":-2.01,\"clouds\":52,\"wind_speed\":9.7,\"wind_deg\":197,\"wind_gust\":13.49,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617724800,\"temp\":1.68,\"feels_like\":-7.57,\"pressure\":992,\"humidity\":76,\"dew_point\":-1.85,\"clouds\":42,\"wind_speed\":9.97,\"wind_deg\":193,\"wind_gust\":14.21,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617728400,\"temp\":1.67,\"feels_like\":-7.65,\"pressure\":984,\"humidity\":75,\"dew_point\":-2.01,\"clouds\":38,\"wind_speed\":10.04,\"wind_deg\":190,\"wind_gust\":14.59,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617732000,\"temp\":1.67,\"feels_like\":-8.41,\"pressure\":984,\"humidity\":73,\"dew_point\":-2.34,\"clouds\":37,\"wind_speed\":11.06,\"wind_deg\":191,\"wind_gust\":16.02,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617735600,\"temp\":1.11,\"feels_like\":-9.22,\"pressure\":985,\"humidity\":73,\"dew_point\":-2.82,\"clouds\":56,\"wind_speed\":11.32,\"wind_deg\":195,\"wind_gust\":16.33,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}]},{\"dt\":1617739200,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617742800,\"temp\":0.56,\"feels_like\":-9.73,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":26,\"wind_speed\":11.14,\"wind_deg\":202,\"wind_gust\":16.22,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617746400,\"temp\":0.56,\"feels_like\":-9.57,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":21,\"wind_speed\":10.92,\"wind_deg\":206,\"wind_gust\":16.09,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]},{\"dt\":1617750000,\"temp\":0,\"feels_like\":-9.73,\"pressure\":987,\"humidity\":74,\"dew_point\":-3.61,\"clouds\":19,\"wind_speed\":10.31,\"wind_deg\":207,\"wind_gust\":15.05,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]}]}"; + + } + + @Test + public void mapToHistorical_withInvalidJSON() { + final String jsonString = "{\"lat\":60.99lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"current\":{\"dt\":1617739371,\"sunrise\":1617678248,\"sunset\":1617727984,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"uvi\":1.69,\"clouds\":33,\"wind_speed\":11.04,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},\"hourly\":[{\"dt\":1617667200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617670800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617674400,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617678000,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617681600,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617685200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617688800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617692400,\"temp\":0.49,\"feels_like\":-7.81,\"pressure\":988,\"humidity\":76,\"dew_point\":-2.87,\"clouds\":100,\"wind_speed\":8.41,\"wind_deg\":196,\"wind_gust\":10.8,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617696000,\"temp\":0.74,\"feels_like\":-7.87,\"pressure\":988,\"humidity\":74,\"dew_point\":-2.97,\"clouds\":100,\"wind_speed\":8.83,\"wind_deg\":196,\"wind_gust\":11.38,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617699600,\"temp\":0.98,\"feels_like\":-7.65,\"pressure\":989,\"humidity\":69,\"dew_point\":-3.59,\"clouds\":99,\"wind_speed\":8.75,\"wind_deg\":203,\"wind_gust\":11.54,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617703200,\"temp\":1.18,\"feels_like\":-7.24,\"pressure\":989,\"humidity\":67,\"dew_point\":-3.77,\"clouds\":86,\"wind_speed\":8.41,\"wind_deg\":205,\"wind_gust\":11.41,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617706800,\"temp\":1.39,\"feels_like\":-6.84,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.77,\"clouds\":77,\"wind_speed\":8.15,\"wind_deg\":199,\"wind_gust\":10.92,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617710400,\"temp\":1.53,\"feels_like\":-6.93,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.65,\"clouds\":42,\"wind_speed\":8.49,\"wind_deg\":191,\"wind_gust\":11.93,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617714000,\"temp\":1.76,\"feels_like\":-7.16,\"pressure\":991,\"humidity\":66,\"dew_point\":-3.46,\"clouds\":47,\"wind_speed\":9.19,\"wind_deg\":199,\"wind_gust\":13.07,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617717600,\"temp\":1.64,\"feels_like\":-7.85,\"pressure\":991,\"humidity\":72,\"dew_point\":-2.53,\"clouds\":67,\"wind_speed\":10.18,\"wind_deg\":205,\"wind_gust\":13.98,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617721200,\"temp\":1.49,\"feels_like\":-7.59,\"pressure\":991,\"humidity\":76,\"dew_point\":-2.01,\"clouds\":52,\"wind_speed\":9.7,\"wind_deg\":197,\"wind_gust\":13.49,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617724800,\"temp\":1.68,\"feels_like\":-7.57,\"pressure\":992,\"humidity\":76,\"dew_point\":-1.85,\"clouds\":42,\"wind_speed\":9.97,\"wind_deg\":193,\"wind_gust\":14.21,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617728400,\"temp\":1.67,\"feels_like\":-7.65,\"pressure\":984,\"humidity\":75,\"dew_point\":-2.01,\"clouds\":38,\"wind_speed\":10.04,\"wind_deg\":190,\"wind_gust\":14.59,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617732000,\"temp\":1.67,\"feels_like\":-8.41,\"pressure\":984,\"humidity\":73,\"dew_point\":-2.34,\"clouds\":37,\"wind_speed\":11.06,\"wind_deg\":191,\"wind_gust\":16.02,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617735600,\"temp\":1.11,\"feels_like\":-9.22,\"pressure\":985,\"humidity\":73,\"dew_point\":-2.82,\"clouds\":56,\"wind_speed\":11.32,\"wind_deg\":195,\"wind_gust\":16.33,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}]},{\"dt\":1617739200,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617742800,\"temp\":0.56,\"feels_like\":-9.73,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":26,\"wind_speed\":11.14,\"wind_deg\":202,\"wind_gust\":16.22,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617746400,\"temp\":0.56,\"feels_like\":-9.57,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":21,\"wind_speed\":10.92,\"wind_deg\":206,\"wind_gust\":16.09,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]},{\"dt\":1617750000,\"temp\":0,\"feels_like\":-9.73,\"pressure\":987,\"humidity\":74,\"dew_point\":-3.61,\"clouds\":19,\"wind_speed\":10.31,\"wind_deg\":207,\"wind_gust\":15.05,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]}]}"; + + assertThrows(RuntimeException.class, () -> new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToHistorical(jsonString)); + } + + @Test + public void mapToHistorical_withWeatherVariants() { + String jsonString = "{\"lat\":60.99,\"lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"hourly\":[{\"dt\":1617667200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617670800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617674400,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617678000,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617681600,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617685200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617688800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617692400,\"temp\":0.49,\"feels_like\":-7.81,\"pressure\":988,\"humidity\":76,\"dew_point\":-2.87,\"clouds\":100,\"wind_speed\":8.41,\"wind_deg\":196,\"wind_gust\":10.8,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617696000,\"temp\":0.74,\"feels_like\":-7.87,\"pressure\":988,\"humidity\":74,\"dew_point\":-2.97,\"clouds\":100,\"wind_speed\":8.83,\"wind_deg\":196,\"wind_gust\":11.38,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617699600,\"temp\":0.98,\"feels_like\":-7.65,\"pressure\":989,\"humidity\":69,\"dew_point\":-3.59,\"clouds\":99,\"wind_speed\":8.75,\"wind_deg\":203,\"wind_gust\":11.54,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617703200,\"temp\":1.18,\"feels_like\":-7.24,\"pressure\":989,\"humidity\":67,\"dew_point\":-3.77,\"clouds\":86,\"wind_speed\":8.41,\"wind_deg\":205,\"wind_gust\":11.41,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617706800,\"temp\":1.39,\"feels_like\":-6.84,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.77,\"clouds\":77,\"wind_speed\":8.15,\"wind_deg\":199,\"wind_gust\":10.92,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617710400,\"temp\":1.53,\"feels_like\":-6.93,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.65,\"clouds\":42,\"wind_speed\":8.49,\"wind_deg\":191,\"wind_gust\":11.93,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617714000,\"temp\":1.76,\"feels_like\":-7.16,\"pressure\":991,\"humidity\":66,\"dew_point\":-3.46,\"clouds\":47,\"wind_speed\":9.19,\"wind_deg\":199,\"wind_gust\":13.07,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617717600,\"temp\":1.64,\"feels_like\":-7.85,\"pressure\":991,\"humidity\":72,\"dew_point\":-2.53,\"clouds\":67,\"wind_speed\":10.18,\"wind_deg\":205,\"wind_gust\":13.98,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617721200,\"temp\":1.49,\"feels_like\":-7.59,\"pressure\":991,\"humidity\":76,\"dew_point\":-2.01,\"clouds\":52,\"wind_speed\":9.7,\"wind_deg\":197,\"wind_gust\":13.49,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617724800,\"temp\":1.68,\"feels_like\":-7.57,\"pressure\":992,\"humidity\":76,\"dew_point\":-1.85,\"clouds\":42,\"wind_speed\":9.97,\"wind_deg\":193,\"wind_gust\":14.21,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617728400,\"temp\":1.67,\"feels_like\":-7.65,\"pressure\":984,\"humidity\":75,\"dew_point\":-2.01,\"clouds\":38,\"wind_speed\":10.04,\"wind_deg\":190,\"wind_gust\":14.59,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617732000,\"temp\":1.67,\"feels_like\":-8.41,\"pressure\":984,\"humidity\":73,\"dew_point\":-2.34,\"clouds\":37,\"wind_speed\":11.06,\"wind_deg\":191,\"wind_gust\":16.02,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617735600,\"temp\":1.11,\"feels_like\":-9.22,\"pressure\":985,\"humidity\":73,\"dew_point\":-2.82,\"clouds\":56,\"wind_speed\":11.32,\"wind_deg\":195,\"wind_gust\":16.33,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}]},{\"dt\":1617739200,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617742800,\"temp\":0.56,\"feels_like\":-9.73,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":26,\"wind_speed\":11.14,\"wind_deg\":202,\"wind_gust\":16.22,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617746400,\"temp\":0.56,\"feels_like\":-9.57,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":21,\"wind_speed\":10.92,\"wind_gust\":16.09,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]},{\"dt\":1617750000,\"temp\":0,\"feels_like\":-9.73,\"pressure\":987,\"humidity\":74,\"dew_point\":-3.61,\"clouds\":19,\"wind_speed\":10.31,\"wind_deg\":207,\"wind_gust\":15.05,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]}]}"; + HistoricalWeatherData historicalWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToHistorical(jsonString); + + assertNotNull(historicalWeatherData); + assertNull(historicalWeatherData.getHistoricalWeather()); + + jsonString = "{\"lat\":60.99,\"lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"current\":{\"dt\":1617739371,\"sunrise\":1617678248,\"sunset\":1617727984,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"uvi\":1.69,\"visibility\":20000,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},\"hourly\":[{\"dt\":1617667200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617670800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617674400,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617678000,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617681600,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617685200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617688800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617692400,\"temp\":0.49,\"feels_like\":-7.81,\"pressure\":988,\"humidity\":76,\"dew_point\":-2.87,\"clouds\":100,\"wind_speed\":8.41,\"wind_deg\":196,\"wind_gust\":10.8,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617696000,\"temp\":0.74,\"feels_like\":-7.87,\"pressure\":988,\"humidity\":74,\"dew_point\":-2.97,\"clouds\":100,\"wind_speed\":8.83,\"wind_deg\":196,\"wind_gust\":11.38,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617699600,\"temp\":0.98,\"feels_like\":-7.65,\"pressure\":989,\"humidity\":69,\"dew_point\":-3.59,\"clouds\":99,\"wind_speed\":8.75,\"wind_deg\":203,\"wind_gust\":11.54,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617703200,\"temp\":1.18,\"feels_like\":-7.24,\"pressure\":989,\"humidity\":67,\"dew_point\":-3.77,\"clouds\":86,\"wind_speed\":8.41,\"wind_deg\":205,\"wind_gust\":11.41,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617706800,\"temp\":1.39,\"feels_like\":-6.84,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.77,\"clouds\":77,\"wind_speed\":8.15,\"wind_deg\":199,\"wind_gust\":10.92,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617710400,\"temp\":1.53,\"feels_like\":-6.93,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.65,\"clouds\":42,\"wind_speed\":8.49,\"wind_deg\":191,\"wind_gust\":11.93,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617714000,\"temp\":1.76,\"feels_like\":-7.16,\"pressure\":991,\"humidity\":66,\"dew_point\":-3.46,\"clouds\":47,\"wind_speed\":9.19,\"wind_deg\":199,\"wind_gust\":13.07,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617717600,\"temp\":1.64,\"feels_like\":-7.85,\"pressure\":991,\"humidity\":72,\"dew_point\":-2.53,\"clouds\":67,\"wind_speed\":10.18,\"wind_deg\":205,\"wind_gust\":13.98,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617721200,\"temp\":1.49,\"feels_like\":-7.59,\"pressure\":991,\"humidity\":76,\"dew_point\":-2.01,\"clouds\":52,\"wind_speed\":9.7,\"wind_deg\":197,\"wind_gust\":13.49,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617724800,\"temp\":1.68,\"feels_like\":-7.57,\"pressure\":992,\"humidity\":76,\"dew_point\":-1.85,\"clouds\":42,\"wind_speed\":9.97,\"wind_deg\":193,\"wind_gust\":14.21,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617728400,\"temp\":1.67,\"feels_like\":-7.65,\"pressure\":984,\"humidity\":75,\"dew_point\":-2.01,\"clouds\":38,\"wind_speed\":10.04,\"wind_deg\":190,\"wind_gust\":14.59,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617732000,\"temp\":1.67,\"feels_like\":-8.41,\"pressure\":984,\"humidity\":73,\"dew_point\":-2.34,\"clouds\":37,\"wind_speed\":11.06,\"wind_deg\":191,\"wind_gust\":16.02,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617735600,\"temp\":1.11,\"feels_like\":-9.22,\"pressure\":985,\"humidity\":73,\"dew_point\":-2.82,\"clouds\":56,\"wind_speed\":11.32,\"wind_deg\":195,\"wind_gust\":16.33,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}]},{\"dt\":1617739200,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617742800,\"temp\":0.56,\"feels_like\":-9.73,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":26,\"wind_deg\":202,\"wind_gust\":16.22,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617746400,\"temp\":0.56,\"feels_like\":-9.57,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":21,\"wind_speed\":10.92,\"wind_deg\":206,\"wind_gust\":16.09,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]},{\"dt\":1617750000,\"temp\":0,\"feels_like\":-9.73,\"pressure\":987,\"humidity\":74,\"dew_point\":-3.61,\"clouds\":19,\"wind_speed\":10.31,\"wind_deg\":207,\"wind_gust\":15.05,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]}]}"; + historicalWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToHistorical(jsonString); + + assertNotNull(historicalWeatherData); + assertNotNull(historicalWeatherData.getHistoricalWeather()); + assertEquals(20000, historicalWeatherData.getHistoricalWeather().getVisibilityInMetres(), 0.00001); + } + + @Test + public void mapToHistorical_withHourlyHistoricalVariants() { + String jsonString = "{\"lat\":60.99,\"lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"current\":{\"dt\":1617739371,\"sunrise\":1617678248,\"sunset\":1617727984,\"temp\":0,\"pressure\":986,\"humidity\":73,\"uvi\":1.69,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[]}}"; + HistoricalWeatherData historicalWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToHistorical(jsonString); + + assertNotNull(historicalWeatherData); + assertNull(historicalWeatherData.getHourlyList()); + + jsonString = "{\"lat\":60.99,\"lon\":30.9,\"timezone\":\"Europe/Moscow\",\"timezone_offset\":10800,\"current\":{\"dt\":1617739371,\"sunrise\":1617678248,\"sunset\":1617727984,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"uvi\":1.69,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97},\"hourly\":[{\"dt\":1617667200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617670800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617674400,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"visibility\":20000,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617678000,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04n\"}]},{\"dt\":1617681600,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617685200,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617688800,\"temp\":0.22,\"feels_like\":-7.76,\"pressure\":988,\"humidity\":80,\"dew_point\":-2.49,\"clouds\":100,\"wind_speed\":8.02,\"wind_deg\":199,\"wind_gust\":10.5,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617692400,\"temp\":0.49,\"feels_like\":-7.81,\"pressure\":988,\"humidity\":76,\"dew_point\":-2.87,\"clouds\":100,\"wind_speed\":8.41,\"wind_deg\":196,\"wind_gust\":10.8,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617696000,\"temp\":0.74,\"feels_like\":-7.87,\"pressure\":988,\"humidity\":74,\"dew_point\":-2.97,\"clouds\":100,\"wind_speed\":8.83,\"wind_deg\":196,\"wind_gust\":11.38,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617699600,\"temp\":0.98,\"feels_like\":-7.65,\"pressure\":989,\"humidity\":69,\"dew_point\":-3.59,\"clouds\":99,\"wind_speed\":8.75,\"wind_deg\":203,\"wind_gust\":11.54,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617703200,\"temp\":1.18,\"feels_like\":-7.24,\"pressure\":989,\"humidity\":67,\"dew_point\":-3.77,\"clouds\":86,\"wind_speed\":8.41,\"wind_deg\":205,\"wind_gust\":11.41,\"weather\":[{\"id\":804,\"main\":\"Clouds\",\"description\":\"overcast clouds\",\"icon\":\"04d\"}]},{\"dt\":1617706800,\"temp\":1.39,\"feels_like\":-6.84,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.77,\"clouds\":77,\"wind_speed\":8.15,\"wind_deg\":199,\"wind_gust\":10.92,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617710400,\"temp\":1.53,\"feels_like\":-6.93,\"pressure\":990,\"humidity\":66,\"dew_point\":-3.65,\"clouds\":42,\"wind_speed\":8.49,\"wind_deg\":191,\"wind_gust\":11.93,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617714000,\"temp\":1.76,\"feels_like\":-7.16,\"pressure\":991,\"humidity\":66,\"dew_point\":-3.46,\"clouds\":47,\"wind_speed\":9.19,\"wind_deg\":199,\"wind_gust\":13.07,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617717600,\"temp\":1.64,\"feels_like\":-7.85,\"pressure\":991,\"humidity\":72,\"dew_point\":-2.53,\"clouds\":67,\"wind_speed\":10.18,\"wind_deg\":205,\"wind_gust\":13.98,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617721200,\"temp\":1.49,\"feels_like\":-7.59,\"pressure\":991,\"humidity\":76,\"dew_point\":-2.01,\"clouds\":52,\"wind_speed\":9.7,\"wind_deg\":197,\"wind_gust\":13.49,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04d\"}]},{\"dt\":1617724800,\"temp\":1.68,\"feels_like\":-7.57,\"pressure\":992,\"humidity\":76,\"dew_point\":-1.85,\"clouds\":42,\"wind_speed\":9.97,\"wind_deg\":193,\"wind_gust\":14.21,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03d\"}]},{\"dt\":1617728400,\"temp\":1.67,\"feels_like\":-7.65,\"pressure\":984,\"humidity\":75,\"dew_point\":-2.01,\"clouds\":38,\"wind_speed\":10.04,\"wind_deg\":190,\"wind_gust\":14.59,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617732000,\"temp\":1.67,\"feels_like\":-8.41,\"pressure\":984,\"humidity\":73,\"dew_point\":-2.34,\"clouds\":37,\"wind_speed\":11.06,\"wind_deg\":191,\"wind_gust\":16.02,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617735600,\"temp\":1.11,\"feels_like\":-9.22,\"pressure\":985,\"humidity\":73,\"dew_point\":-2.82,\"clouds\":56,\"wind_speed\":11.32,\"wind_deg\":195,\"wind_gust\":16.33,\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"broken clouds\",\"icon\":\"04n\"}]},{\"dt\":1617739200,\"temp\":0,\"feels_like\":-10.26,\"pressure\":986,\"humidity\":73,\"dew_point\":-3.77,\"clouds\":33,\"wind_speed\":11.04,\"wind_deg\":196,\"wind_gust\":15.97,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617742800,\"temp\":0.56,\"feels_like\":-9.73,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":26,\"wind_speed\":11.14,\"wind_deg\":202,\"wind_gust\":16.22,\"weather\":[{\"id\":802,\"main\":\"Clouds\",\"description\":\"scattered clouds\",\"icon\":\"03n\"}]},{\"dt\":1617746400,\"temp\":0.56,\"feels_like\":-9.57,\"pressure\":986,\"humidity\":72,\"dew_point\":-3.45,\"clouds\":21,\"wind_speed\":10.92,\"wind_deg\":206,\"wind_gust\":16.09,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]},{\"dt\":1617750000,\"temp\":0,\"feels_like\":-9.73,\"pressure\":987,\"humidity\":74,\"dew_point\":-3.61,\"clouds\":19,\"wind_speed\":10.31,\"wind_deg\":207,\"wind_gust\":15.05,\"weather\":[{\"id\":801,\"main\":\"Clouds\",\"description\":\"few clouds\",\"icon\":\"02n\"}]}]}"; + historicalWeatherData = new OneCallWeatherResponseMapper(UnitSystem.METRIC).mapToHistorical(jsonString); + + assertNotNull(historicalWeatherData); + assertNotNull(historicalWeatherData.getHourlyList()); + historicalWeatherData.getHourlyList().forEach(Assertions::assertNotNull); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallIntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallIntegrationTest.java new file mode 100644 index 0000000..2ed6d27 --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/current/CurrentWeatherOneCallIntegrationTest.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.current; + +import com.github.prominence.openweathermap.api.ApiTest; +import com.github.prominence.openweathermap.api.OpenWeatherMapClient; +import com.github.prominence.openweathermap.api.enums.Language; +import com.github.prominence.openweathermap.api.enums.OneCallResultOptions; +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException; +import com.github.prominence.openweathermap.api.exception.NoDataFoundException; +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.model.onecall.current.CurrentWeatherData; +import org.junit.jupiter.api.Test; + +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.*; + +public class CurrentWeatherOneCallIntegrationTest extends ApiTest { + @Test + public void whenRetrieveCurrentOneCallResponseAsJava_thenOk() { + final CurrentWeatherData currentWeatherData = getClient() + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); + + assertNotNull(currentWeatherData); + } + + @Test + public void whenRetrieveCurrentOneCallResponseAsJSON_thenOk() { + final String responseJson = getClient() + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); + + assertNotNull(responseJson); + assertNotEquals("", responseJson); + System.out.println(responseJson); + } + + @Test + public void whenRetrieveCurrentOneCallResponseWithExclusionAsJava_thenOk() { + final CurrentWeatherData currentWeatherData = getClient() + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .exclude(OneCallResultOptions.CURRENT, OneCallResultOptions.MINUTELY) + .retrieve() + .asJava(); + + assertNotNull(currentWeatherData); + assertNull(currentWeatherData.getCurrent()); + assertNull(currentWeatherData.getMinutelyList()); + } + + @Test + public void whenRetrieveCurrentOneCallAsyncResponseAsJava_thenOk() throws ExecutionException, InterruptedException { + final CompletableFuture currentWeatherDataFuture = getClient() + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); + + assertNotNull(currentWeatherDataFuture); + assertNotNull(currentWeatherDataFuture.get()); + } + + @Test + public void whenRetrieveCurrentOneCallAsyncResponseAsJSON_thenOk() throws ExecutionException, InterruptedException { + final CompletableFuture responseJsonFuture = getClient() + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJSON(); + + assertNotNull(responseJsonFuture); + final String responseJson = responseJsonFuture.get(); + assertNotNull(responseJson); + System.out.println(responseJson); + } + + @Test + public void whenRequestOnecallWithInvalidApiKey_thenThrowAnException() { + OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey"); + assertThrows(InvalidAuthTokenException.class, () -> + client + .oneCall() + .current() + .byCoordinate(Coordinate.of(53.54, 27.34)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON() + ); + } +} diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/onecall/historical/HistoricalWeatherOneCallIntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/historical/HistoricalWeatherOneCallIntegrationTest.java new file mode 100644 index 0000000..d7d2ecf --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/request/onecall/historical/HistoricalWeatherOneCallIntegrationTest.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.onecall.historical; + +import com.github.prominence.openweathermap.api.ApiTest; +import com.github.prominence.openweathermap.api.OpenWeatherMapClient; +import com.github.prominence.openweathermap.api.enums.Language; +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.exception.InvalidAuthTokenException; +import com.github.prominence.openweathermap.api.exception.NoDataFoundException; +import com.github.prominence.openweathermap.api.model.Coordinate; +import com.github.prominence.openweathermap.api.model.onecall.historical.HistoricalWeatherData; +import org.junit.jupiter.api.Test; + +import java.time.LocalDateTime; +import java.time.ZoneOffset; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; + +import static org.junit.jupiter.api.Assertions.*; + +public class HistoricalWeatherOneCallIntegrationTest extends ApiTest { + @Test + public void whenRetrieveHistoricalOneCallResponseAsJava_thenOk() { + final HistoricalWeatherData historicalWeatherData = getClient() + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJava(); + + assertNotNull(historicalWeatherData); + } + + @Test + public void whenRetrieveHistoricalOneCallResponseAsJSON_thenOk() { + final String responseJson = getClient() + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON(); + + assertNotNull(responseJson); + assertNotEquals("", responseJson); + System.out.println(responseJson); + } + + @Test + public void whenRetrieveHistoricalOneCallAsyncResponseAsJava_thenOk() throws ExecutionException, InterruptedException { + final CompletableFuture historicalWeatherDataFuture = getClient() + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJava(); + + assertNotNull(historicalWeatherDataFuture); + assertNotNull(historicalWeatherDataFuture.get()); + } + + @Test + public void whenRetrieveHistoricalOneCallAsyncResponseAsJSON_thenOk() throws ExecutionException, InterruptedException { + final CompletableFuture responseJsonFuture = getClient() + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(60.99, 30.9), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieveAsync() + .asJSON(); + + assertNotNull(responseJsonFuture); + final String responseJson = responseJsonFuture.get(); + assertNotEquals("", responseJson); + System.out.println(responseJson); + } + + @Test + public void whenRequestOnecallWithInvalidApiKey_thenThrowAnException() { + OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey"); + assertThrows(InvalidAuthTokenException.class, () -> + client + .oneCall() + .historical() + .byCoordinateAndTimestamp(Coordinate.of(53.54, 27.34), LocalDateTime.now().minusDays(5).toEpochSecond(ZoneOffset.UTC)) + .language(Language.ENGLISH) + .unitSystem(UnitSystem.METRIC) + .retrieve() + .asJSON() + ); + } +} diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapperUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapperUnitTest.java new file mode 100644 index 0000000..fa44fcf --- /dev/null +++ b/src/test/java/com/github/prominence/openweathermap/api/request/weather/CurrentWeatherResponseMapperUnitTest.java @@ -0,0 +1,244 @@ +/* + * Copyright (c) 2021 Alexey Zinchenko + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package com.github.prominence.openweathermap.api.request.weather; + +import com.github.prominence.openweathermap.api.enums.UnitSystem; +import com.github.prominence.openweathermap.api.model.weather.Weather; +import org.junit.jupiter.api.Test; + +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; + +public class CurrentWeatherResponseMapperUnitTest { + @Test + public void getSingle() { + final String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final Weather weather = new CurrentWeatherResponseMapper(UnitSystem.METRIC).getSingle(jsonString); + + assertNotNull(weather); + } + + @Test + public void getSingle_withDamagedJSON() { + final String jsonString = "{\"coord\":\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + assertThrows(RuntimeException.class, () -> new CurrentWeatherResponseMapper(null).getSingle(jsonString)); + } + + @Test + public void getSingle_withoutDt() { + final String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final Weather weather = new CurrentWeatherResponseMapper(UnitSystem.METRIC).getSingle(jsonString); + + assertNotNull(weather); + assertNull(weather.getCalculationTime()); + } + + @Test + public void getSingle_withoutWeatherNode() { + final String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final Weather weather = new CurrentWeatherResponseMapper(UnitSystem.METRIC).getSingle(jsonString); + + assertNotNull(weather); + assertNull(weather.getWeatherState()); + } + + @Test + public void getSingle_withTemperatureVariations() { + String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final CurrentWeatherResponseMapper mapper = new CurrentWeatherResponseMapper(UnitSystem.METRIC); + + Weather weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertEquals(1.84, weather.getTemperature().getValue(), 0.00001); + assertEquals(-0.31, weather.getTemperature().getFeelsLike(), 0.00001); + assertEquals(1.67, weather.getTemperature().getMinTemperature(), 0.00001); + assertEquals(2, weather.getTemperature().getMaxTemperature(), 0.00001); + + // without feels like node + jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertNotNull(weather.getTemperature()); + assertNull(weather.getTemperature().getFeelsLike()); + assertNotNull(weather.getTemperature().getMinTemperature()); + assertNotNull(weather.getTemperature().getMaxTemperature()); + + // without min temperature node + jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getTemperature().getFeelsLike()); + assertNull(weather.getTemperature().getMinTemperature()); + assertNotNull(weather.getTemperature().getMaxTemperature()); + + // without max temperature node + jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getTemperature().getFeelsLike()); + assertNotNull(weather.getTemperature().getMinTemperature()); + assertNull(weather.getTemperature().getMaxTemperature()); + } + + @Test + public void getSingle_withWindVariations() { + String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final CurrentWeatherResponseMapper mapper = new CurrentWeatherResponseMapper(UnitSystem.METRIC); + Weather weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertEquals(2, weather.getWind().getSpeed(), 0.00001); + assertEquals(250, weather.getWind().getDegrees(), 0.00001); + assertNull(weather.getWind().getGust()); + + // without degrees + jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertNotNull(weather.getWind()); + assertNull(weather.getWind().getDegrees()); + + // with gust + jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250, \"gust\": 2.44},\"snow\":{\"1h\":0.2},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + + assertNotNull(weather); + assertNotNull(weather.getWind()); + assertNotNull(weather.getWind().getDegrees()); + assertEquals(2.44, weather.getWind().getGust(), 0.00001); + } + + @Test + public void getSingle_withRainVariations() { + final String jsonWith1Hr = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"rain\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final String jsonWith3Hr = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"rain\":{\"3h\":0.3},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final String jsonWithBoth = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"rain\":{\"1h\":0.1, \"3h\":0.3},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final CurrentWeatherResponseMapper mapper = new CurrentWeatherResponseMapper(UnitSystem.METRIC); + Weather weather = mapper.getSingle(jsonWith1Hr); + + // with 1h level only + assertNotNull(weather.getRain()); + assertEquals(0.1, weather.getRain().getOneHourLevel(), 0.00001); + assertNull(weather.getRain().getThreeHourLevel()); + + weather = mapper.getSingle(jsonWith3Hr); + + // with 3h level only + assertNotNull(weather.getRain()); + assertNull(weather.getRain().getOneHourLevel()); + assertEquals(0.3, weather.getRain().getThreeHourLevel(), 0.00001); + + weather = mapper.getSingle(jsonWithBoth); + + // with both levels + assertNotNull(weather.getRain()); + assertEquals(0.1, weather.getRain().getOneHourLevel(), 0.00001); + assertEquals(0.3, weather.getRain().getThreeHourLevel(), 0.00001); + } + + @Test + public void getSingle_withSnowVariations() { + final String jsonWith1Hr = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final String jsonWith3Hr = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"3h\":0.3},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final String jsonWithBoth = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1, \"3h\":0.3},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + + final CurrentWeatherResponseMapper mapper = new CurrentWeatherResponseMapper(UnitSystem.METRIC); + Weather weather = mapper.getSingle(jsonWith1Hr); + + // with 1h level only + assertNotNull(weather.getSnow()); + assertEquals(0.1, weather.getSnow().getOneHourLevel(), 0.00001); + assertNull(weather.getSnow().getThreeHourLevel()); + + weather = mapper.getSingle(jsonWith3Hr); + + // with 3h level only + assertNotNull(weather.getSnow()); + assertNull(weather.getSnow().getOneHourLevel()); + assertEquals(0.3, weather.getSnow().getThreeHourLevel(), 0.00001); + + weather = mapper.getSingle(jsonWithBoth); + + // with both levels + assertNotNull(weather.getSnow()); + assertEquals(0.1, weather.getSnow().getOneHourLevel(), 0.00001); + assertEquals(0.3, weather.getSnow().getThreeHourLevel(), 0.00001); + } + + @Test + public void getSingle_withLocationVariations() { + String jsonString = "{\"coord\":{\"lon\":27.5667,\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + final CurrentWeatherResponseMapper mapper = new CurrentWeatherResponseMapper(UnitSystem.METRIC); + + Weather weather = mapper.getSingle(jsonString); + + assertNotNull(weather.getLocation().getCoordinate()); + assertNotNull(weather.getLocation().getCountryCode()); + + // without coordinates and country code + jsonString = "{\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + assertNull(weather.getLocation().getCoordinate()); + assertNull(weather.getLocation().getCountryCode()); + + // coordinates without latitude + jsonString = "{\"coord\":{\"lon\":27.5667},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + assertNull(weather.getLocation().getCoordinate()); + assertNotNull(weather.getLocation().getCountryCode()); + + // coordinates without longitude + jsonString = "{\"coord\":{\"lat\":53.9},\"weather\":[{\"id\":600,\"main\":\"Snow\",\"description\":\"небольшой снег\",\"icon\":\"13n\"}],\"base\":\"stations\",\"main\":{\"temp\":1.84,\"feels_like\":-0.31,\"temp_min\":1.67,\"temp_max\":2,\"pressure\":1001,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":2,\"deg\":250},\"snow\":{\"1h\":0.1},\"clouds\":{\"all\":75},\"dt\":1617746826,\"sys\":{\"type\":1,\"id\":8939,\"country\":\"BY\",\"sunrise\":1617766068,\"sunset\":1617814530},\"timezone\":10800,\"id\":0,\"name\":\"Minsk\",\"cod\":200}"; + weather = mapper.getSingle(jsonString); + assertNull(weather.getLocation().getCoordinate()); + assertNotNull(weather.getLocation().getCountryCode()); + } + + @Test + public void getList() { + final String jsonString = "{\"cod\":200,\"calctime\":0.002580978,\"cnt\":15,\"list\":[{\"id\":2563191,\"dt\":1617746970,\"name\":\"Birkirkara\",\"coord\":{\"Lon\":14.4611,\"Lat\":35.8972},\"main\":{\"temp\":14.42,\"feels_like\":11.94,\"temp_min\":14,\"temp_max\":15,\"pressure\":1013,\"humidity\":88},\"visibility\":10000,\"wind\":{\"speed\":4.63,\"deg\":240},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2210247,\"dt\":1617746968,\"name\":\"Tripoli\",\"coord\":{\"Lon\":13.1875,\"Lat\":32.8752},\"main\":{\"temp\":16.44,\"feels_like\":14.28,\"temp_min\":16.44,\"temp_max\":16.44,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1013,\"humidity\":65},\"visibility\":10000,\"wind\":{\"speed\":3.09,\"deg\":150},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2216885,\"dt\":1617746968,\"name\":\"Zawiya\",\"coord\":{\"Lon\":12.7278,\"Lat\":32.7522},\"main\":{\"temp\":16.87,\"feels_like\":14.35,\"temp_min\":16.87,\"temp_max\":16.87,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1013,\"humidity\":60},\"visibility\":10000,\"wind\":{\"speed\":3.31,\"deg\":135},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2212771,\"dt\":1617746968,\"name\":\"Şabrātah\",\"coord\":{\"Lon\":12.4885,\"Lat\":32.7933},\"main\":{\"temp\":16.51,\"feels_like\":13.71,\"temp_min\":16.51,\"temp_max\":16.51,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1014,\"humidity\":61},\"visibility\":10000,\"wind\":{\"speed\":3.67,\"deg\":136},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2215163,\"dt\":1617746968,\"name\":\"Masallātah\",\"coord\":{\"Lon\":14,\"Lat\":32.6167},\"main\":{\"temp\":14.09,\"feels_like\":13.24,\"temp_min\":14.09,\"temp_max\":14.09,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":989,\"humidity\":68},\"visibility\":10000,\"wind\":{\"speed\":0.64,\"deg\":226},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2219905,\"dt\":1617746968,\"name\":\"Al Khums\",\"coord\":{\"Lon\":14.2619,\"Lat\":32.6486},\"main\":{\"temp\":15.7,\"feels_like\":15.67,\"temp_min\":15.7,\"temp_max\":15.7,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":1014,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":0.12,\"deg\":348},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2208425,\"dt\":1617746968,\"name\":\"Zuwārah\",\"coord\":{\"Lon\":12.082,\"Lat\":32.9312},\"main\":{\"temp\":16.55,\"feels_like\":13.33,\"temp_min\":16.55,\"temp_max\":16.55,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1015,\"humidity\":67},\"visibility\":10000,\"wind\":{\"speed\":4.82,\"deg\":145},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2210221,\"dt\":1617746968,\"name\":\"Tarhuna\",\"coord\":{\"Lon\":13.6332,\"Lat\":32.435},\"main\":{\"temp\":13.37,\"feels_like\":12.26,\"temp_min\":13.37,\"temp_max\":13.37,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":970,\"humidity\":62},\"visibility\":10000,\"wind\":{\"speed\":0.35,\"deg\":135},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2208485,\"dt\":1617746968,\"name\":\"Zliten\",\"coord\":{\"Lon\":14.5687,\"Lat\":32.4674},\"main\":{\"temp\":15.76,\"feels_like\":14.69,\"temp_min\":15.76,\"temp_max\":15.76,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":1015,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":1.63,\"deg\":133},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2217362,\"dt\":1617746968,\"name\":\"Gharyan\",\"coord\":{\"Lon\":13.0203,\"Lat\":32.1722},\"main\":{\"temp\":13.79,\"feels_like\":11.83,\"temp_min\":13.79,\"temp_max\":13.79,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":936,\"humidity\":56},\"visibility\":10000,\"wind\":{\"speed\":1.24,\"deg\":188},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2523693,\"dt\":1617746921,\"name\":\"Pozzallo\",\"coord\":{\"Lon\":14.8499,\"Lat\":36.7305},\"main\":{\"temp\":11.65,\"feels_like\":8.3,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2524119,\"dt\":1617746921,\"name\":\"Modica\",\"coord\":{\"Lon\":14.774,\"Lat\":36.8459},\"main\":{\"temp\":11.51,\"feels_like\":8.12,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2208791,\"dt\":1617746968,\"name\":\"Yafran\",\"coord\":{\"Lon\":12.5286,\"Lat\":32.0633},\"main\":{\"temp\":14.29,\"feels_like\":11.33,\"temp_min\":14.29,\"temp_max\":14.29,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":937,\"humidity\":50},\"visibility\":10000,\"wind\":{\"speed\":2.34,\"deg\":142},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2523581,\"dt\":1617746920,\"name\":\"Rosolini\",\"coord\":{\"Lon\":14.9478,\"Lat\":36.8242},\"main\":{\"temp\":11.54,\"feels_like\":8.16,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2523650,\"dt\":1617746922,\"name\":\"Ragusa\",\"coord\":{\"Lon\":14.7172,\"Lat\":36.9282},\"main\":{\"temp\":11.63,\"feels_like\":8.27,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]}]}"; + final List weatherList = new CurrentWeatherResponseMapper(null).getList(jsonString); + + assertNotNull(weatherList); + assertNotEquals(0, weatherList.size()); + } + + @Test + public void getList_withDamagedJSON() { + final String jsonString = "{\"cod\":200,\"calctime\":0.002580978,\"cnt\":15,\"list\":{\"id\":2563191,\"dt\":1617746970,\"name\":\"Birkirkara\",\"coord\":{\"Lon\":14.4611,\"Lat\":35.8972},\"main\":{\"temp\":14.42,\"feels_like\":11.94,\"temp_min\":14,\"temp_max\":15,\"pressure\":1013,\"humidity\":88},\"visibility\":10000,\"wind\":{\"speed\":4.63,\"deg\":240},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2210247,\"dt\":1617746968,\"name\":\"Tripoli\",\"coord\":{\"Lon\":13.1875,\"Lat\":32.8752},\"main\":{\"temp\":16.44,\"feels_like\":14.28,\"temp_min\":16.44,\"temp_max\":16.44,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1013,\"humidity\":65},\"visibility\":10000,\"wind\":{\"speed\":3.09,\"deg\":150},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2216885,\"dt\":1617746968,\"name\":\"Zawiya\",\"coord\":{\"Lon\":12.7278,\"Lat\":32.7522},\"main\":{\"temp\":16.87,\"feels_like\":14.35,\"temp_min\":16.87,\"temp_max\":16.87,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1013,\"humidity\":60},\"visibility\":10000,\"wind\":{\"speed\":3.31,\"deg\":135},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2212771,\"dt\":1617746968,\"name\":\"Şabrātah\",\"coord\":{\"Lon\":12.4885,\"Lat\":32.7933},\"main\":{\"temp\":16.51,\"feels_like\":13.71,\"temp_min\":16.51,\"temp_max\":16.51,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1014,\"humidity\":61},\"visibility\":10000,\"wind\":{\"speed\":3.67,\"deg\":136},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2215163,\"dt\":1617746968,\"name\":\"Masallātah\",\"coord\":{\"Lon\":14,\"Lat\":32.6167},\"main\":{\"temp\":14.09,\"feels_like\":13.24,\"temp_min\":14.09,\"temp_max\":14.09,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":989,\"humidity\":68},\"visibility\":10000,\"wind\":{\"speed\":0.64,\"deg\":226},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2219905,\"dt\":1617746968,\"name\":\"Al Khums\",\"coord\":{\"Lon\":14.2619,\"Lat\":32.6486},\"main\":{\"temp\":15.7,\"feels_like\":15.67,\"temp_min\":15.7,\"temp_max\":15.7,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":1014,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":0.12,\"deg\":348},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2208425,\"dt\":1617746968,\"name\":\"Zuwārah\",\"coord\":{\"Lon\":12.082,\"Lat\":32.9312},\"main\":{\"temp\":16.55,\"feels_like\":13.33,\"temp_min\":16.55,\"temp_max\":16.55,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":1015,\"humidity\":67},\"visibility\":10000,\"wind\":{\"speed\":4.82,\"deg\":145},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2210221,\"dt\":1617746968,\"name\":\"Tarhuna\",\"coord\":{\"Lon\":13.6332,\"Lat\":32.435},\"main\":{\"temp\":13.37,\"feels_like\":12.26,\"temp_min\":13.37,\"temp_max\":13.37,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":970,\"humidity\":62},\"visibility\":10000,\"wind\":{\"speed\":0.35,\"deg\":135},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2208485,\"dt\":1617746968,\"name\":\"Zliten\",\"coord\":{\"Lon\":14.5687,\"Lat\":32.4674},\"main\":{\"temp\":15.76,\"feels_like\":14.69,\"temp_min\":15.76,\"temp_max\":15.76,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":1015,\"humidity\":69},\"visibility\":10000,\"wind\":{\"speed\":1.63,\"deg\":133},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2217362,\"dt\":1617746968,\"name\":\"Gharyan\",\"coord\":{\"Lon\":13.0203,\"Lat\":32.1722},\"main\":{\"temp\":13.79,\"feels_like\":11.83,\"temp_min\":13.79,\"temp_max\":13.79,\"pressure\":1016,\"sea_level\":1016,\"grnd_level\":936,\"humidity\":56},\"visibility\":10000,\"wind\":{\"speed\":1.24,\"deg\":188},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2523693,\"dt\":1617746921,\"name\":\"Pozzallo\",\"coord\":{\"Lon\":14.8499,\"Lat\":36.7305},\"main\":{\"temp\":11.65,\"feels_like\":8.3,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2524119,\"dt\":1617746921,\"name\":\"Modica\",\"coord\":{\"Lon\":14.774,\"Lat\":36.8459},\"main\":{\"temp\":11.51,\"feels_like\":8.12,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2208791,\"dt\":1617746968,\"name\":\"Yafran\",\"coord\":{\"Lon\":12.5286,\"Lat\":32.0633},\"main\":{\"temp\":14.29,\"feels_like\":11.33,\"temp_min\":14.29,\"temp_max\":14.29,\"pressure\":1015,\"sea_level\":1015,\"grnd_level\":937,\"humidity\":50},\"visibility\":10000,\"wind\":{\"speed\":2.34,\"deg\":142},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":0},\"weather\":[{\"id\":800,\"main\":\"Clear\",\"description\":\"cer senin\",\"icon\":\"01n\"}]},{\"id\":2523581,\"dt\":1617746920,\"name\":\"Rosolini\",\"coord\":{\"Lon\":14.9478,\"Lat\":36.8242},\"main\":{\"temp\":11.54,\"feels_like\":8.16,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]},{\"id\":2523650,\"dt\":1617746922,\"name\":\"Ragusa\",\"coord\":{\"Lon\":14.7172,\"Lat\":36.9282},\"main\":{\"temp\":11.63,\"feels_like\":8.27,\"temp_min\":10,\"temp_max\":13,\"pressure\":1012,\"humidity\":94},\"visibility\":10000,\"wind\":{\"speed\":5.14,\"deg\":260},\"rain\":null,\"snow\":null,\"clouds\":{\"today\":75},\"weather\":[{\"id\":803,\"main\":\"Clouds\",\"description\":\"cer fragmentat\",\"icon\":\"04n\"}]}]}"; + assertThrows(RuntimeException.class, () -> new CurrentWeatherResponseMapper(null).getList(jsonString)); + } +} \ No newline at end of file diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherIntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherIntegrationTest.java index 2fb20a9..cb4ea85 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherIntegrationTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/request/weather/multiple/MultipleResultCurrentWeatherIntegrationTest.java @@ -31,13 +31,14 @@ import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.CoordinateRectangle; import com.github.prominence.openweathermap.api.model.weather.Weather; import com.github.prominence.openweathermap.api.OpenWeatherMapClient; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import static org.junit.jupiter.api.Assertions.*; + public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { @Test public void whenGetMultipleCurrentWeatherByCoordinateRectangleRequestAsJava_thenReturnNotNull() { @@ -58,17 +59,16 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weatherList); + assertNotNull(weatherList); for (Weather weather : weatherList) { - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); } } @@ -83,7 +83,7 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -91,24 +91,23 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final List weatherList = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asJava(); - Assert.assertNotNull(weatherList); + assertNotNull(weatherList); for (Weather weather : weatherList) { System.out.println(weather); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); } } @@ -117,13 +116,13 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherJson = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -131,13 +130,13 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherXml = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5)) + .byCitiesInCycle(Coordinate.of(55.5, 37.5)) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); System.out.println(weatherXml); } @@ -146,24 +145,23 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final List weatherList = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5), 10) + .byCitiesInCycle(Coordinate.of(55.5, 37.5), 10) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asJava(); - Assert.assertNotNull(weatherList); + assertNotNull(weatherList); for (Weather weather : weatherList) { System.out.println(weather); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); } } @@ -172,13 +170,13 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherJson = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5), 10) + .byCitiesInCycle(Coordinate.of(55.5, 37.5), 10) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -186,13 +184,13 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherXml = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5), 10) + .byCitiesInCycle(Coordinate.of(55.5, 37.5), 10) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -200,15 +198,15 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final CompletableFuture> weatherListFuture = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5), 10) + .byCitiesInCycle(Coordinate.of(55.5, 37.5), 10) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieveAsync() .asJava(); - Assert.assertNotNull(weatherListFuture); + assertNotNull(weatherListFuture); List weatherList = weatherListFuture.get(); - Assert.assertTrue(weatherList.size() > 0); + assertTrue(weatherList.size() > 0); System.out.println(weatherList); } @@ -217,34 +215,38 @@ public class MultipleResultCurrentWeatherIntegrationTest extends ApiTest { final CompletableFuture weatherFuture = getClient() .currentWeather() .multiple() - .byCitiesInCycle(Coordinate.withValues(55.5, 37.5), 10) + .byCitiesInCycle(Coordinate.of(55.5, 37.5), 10) .language(Language.GERMAN) .unitSystem(UnitSystem.IMPERIAL) .retrieveAsync() .asJSON(); - Assert.assertNotNull(weatherFuture); + assertNotNull(weatherFuture); System.out.println(weatherFuture.get()); } - @Test(expected = InvalidAuthTokenException.class) + @Test public void whenRequestCurrentWeatherWithInvalidApiKey_thenThrowAnException() { OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey"); - client - .currentWeather() - .single() - .byCityName("London") - .retrieve() - .asJSON(); + assertThrows(InvalidAuthTokenException.class, () -> + client + .currentWeather() + .single() + .byCityName("London") + .retrieve() + .asJSON() + ); } - @Test(expected = NoDataFoundException.class) + @Test public void whenRequestCurrentWeatherForInvalidLocation_thenThrowAnException() { - getClient() - .currentWeather() - .single() - .byCityName("InvalidCity") - .retrieve() - .asJava(); + assertThrows(NoDataFoundException.class, () -> + getClient() + .currentWeather() + .single() + .byCityName("InvalidCity") + .retrieve() + .asJava() + ); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherIntegrationTest.java b/src/test/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherIntegrationTest.java index 671fbac..e78faef 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherIntegrationTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/request/weather/single/SingleResultCurrentWeatherIntegrationTest.java @@ -30,12 +30,13 @@ import com.github.prominence.openweathermap.api.exception.NoDataFoundException; import com.github.prominence.openweathermap.api.model.Coordinate; import com.github.prominence.openweathermap.api.model.weather.Weather; import com.github.prominence.openweathermap.api.OpenWeatherMapClient; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; +import static org.junit.jupiter.api.Assertions.*; + public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { @Test public void whenGetSingleCurrentWeatherByCityNameRequestAsJava_thenReturnNotNull() { @@ -48,15 +49,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -71,7 +71,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -85,7 +85,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -99,7 +99,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -113,15 +113,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -136,7 +135,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -150,7 +149,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -164,7 +163,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -178,15 +177,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -201,7 +199,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -215,7 +213,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -229,7 +227,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -242,15 +240,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -264,7 +261,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -277,7 +274,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -290,7 +287,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -298,20 +295,19 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { final Weather weather = getClient() .currentWeather() .single() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .unitSystem(UnitSystem.METRIC) .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -320,12 +316,12 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherJson = getClient() .currentWeather() .single() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .unitSystem(UnitSystem.METRIC) .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -333,12 +329,12 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherXml = getClient() .currentWeather() .single() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .unitSystem(UnitSystem.METRIC) .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -346,12 +342,12 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { final String weatherHtml = getClient() .currentWeather() .single() - .byCoordinate(Coordinate.withValues(5, 5)) + .byCoordinate(Coordinate.of(5, 5)) .unitSystem(UnitSystem.METRIC) .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -365,15 +361,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -388,7 +383,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -402,7 +397,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -416,7 +411,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -430,15 +425,14 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJava(); - Assert.assertNotNull(weather); - Assert.assertNotNull(weather.getState()); - Assert.assertNotNull(weather.getDescription()); - Assert.assertNotNull(weather.getCalculatedOn()); - Assert.assertNotNull(weather.getTemperature()); - Assert.assertNotNull(weather.getLocation()); - Assert.assertNotNull(weather.getAtmosphericPressure()); - Assert.assertNotNull(weather.getHumidity()); - Assert.assertNotNull(weather.getWind()); + assertNotNull(weather); + assertNotNull(weather.getWeatherState()); + assertNotNull(weather.getCalculationTime()); + assertNotNull(weather.getTemperature()); + assertNotNull(weather.getLocation()); + assertNotNull(weather.getAtmosphericPressure()); + assertNotNull(weather.getHumidity()); + assertNotNull(weather.getWind()); System.out.println(weather); } @@ -453,7 +447,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asJSON(); - Assert.assertTrue(weatherJson.startsWith("{")); + assertTrue(weatherJson.startsWith("{")); } @Test @@ -467,7 +461,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asXML(); - Assert.assertTrue(weatherXml.startsWith("<")); + assertTrue(weatherXml.startsWith("<")); } @Test @@ -481,7 +475,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieve() .asHTML(); - Assert.assertTrue(weatherHtml.startsWith("<")); + assertTrue(weatherHtml.startsWith("<")); } @Test @@ -495,7 +489,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieveAsync() .asJava(); - Assert.assertNotNull(weatherFuture); + assertNotNull(weatherFuture); System.out.println(weatherFuture.get()); } @@ -510,7 +504,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieveAsync() .asJSON(); - Assert.assertNotNull(weatherFuture); + assertNotNull(weatherFuture); System.out.println(weatherFuture.get()); } @@ -525,7 +519,7 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieveAsync() .asXML(); - Assert.assertNotNull(weatherXmlFuture); + assertNotNull(weatherXmlFuture); System.out.println(weatherXmlFuture.get()); } @@ -540,28 +534,32 @@ public class SingleResultCurrentWeatherIntegrationTest extends ApiTest { .retrieveAsync() .asHTML(); - Assert.assertNotNull(weatherFuture); + assertNotNull(weatherFuture); System.out.println(weatherFuture.get()); } - @Test(expected = InvalidAuthTokenException.class) + @Test public void whenRequestCurrentWeatherWithInvalidApiKey_thenThrowAnException() { OpenWeatherMapClient client = new OpenWeatherMapClient("invalidKey"); - client - .currentWeather() - .multiple() - .byCitiesInCycle(Coordinate.withValues(34.53, 66.74), 10) - .retrieve() - .asJSON(); + assertThrows(InvalidAuthTokenException.class, () -> + client + .currentWeather() + .multiple() + .byCitiesInCycle(Coordinate.of(34.53, 66.74), 10) + .retrieve() + .asJSON() + ); } - @Test(expected = NoDataFoundException.class) + @Test public void whenRequestCurrentWeatherForInvalidLocation_thenThrowAnException() { - getClient() - .currentWeather() - .multiple() - .byCitiesInCycle(Coordinate.withValues(90.00, 66.74), 10) - .retrieve() - .asJava(); + assertThrows(NoDataFoundException.class, () -> + getClient() + .currentWeather() + .multiple() + .byCitiesInCycle(Coordinate.of(90.00, 66.74), 10) + .retrieve() + .asJava() + ); } } diff --git a/src/test/java/com/github/prominence/openweathermap/api/utils/RequestUtilsUnitTest.java b/src/test/java/com/github/prominence/openweathermap/api/utils/RequestUtilsUnitTest.java index 763f8f7..41264c4 100644 --- a/src/test/java/com/github/prominence/openweathermap/api/utils/RequestUtilsUnitTest.java +++ b/src/test/java/com/github/prominence/openweathermap/api/utils/RequestUtilsUnitTest.java @@ -23,17 +23,18 @@ package com.github.prominence.openweathermap.api.utils; import com.github.prominence.openweathermap.api.exception.NoDataFoundException; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertThrows; public class RequestUtilsUnitTest { - - @Test(expected = IllegalArgumentException.class) + @Test public void whenPassInvalidUrl_thenThrowAnException() { - RequestUtils.getResponse("wrongUrl"); + assertThrows(IllegalArgumentException.class, () -> RequestUtils.getResponse("wrongUrl")); } - @Test(expected = NoDataFoundException.class) + @Test public void whenPassUrlToNonExistingPage_thenThrowAnException() { - RequestUtils.getResponse("https://openweathermap.org/somePage"); + assertThrows(NoDataFoundException.class, () -> RequestUtils.getResponse("https://openweathermap.org/somePage")); } }