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"));
}
}