Compare commits
No commits in common. "bfacaf514aef4f7061e53374ca878b5b3e65ad8a" and "f73311b7a4964d816c576444c60a52f9ec620a8e" have entirely different histories.
bfacaf514a
...
f73311b7a4
31
DESIGN.md
31
DESIGN.md
@ -5,34 +5,33 @@ Notre programme a été pensé pour être le plus évolutif possible, et avec de
|
|||||||
|
|
||||||
Pour se faire le projet est décomposé en plusieurs composants :
|
Pour se faire le projet est décomposé en plusieurs composants :
|
||||||
* L'affichage
|
* L'affichage
|
||||||
* Les APIs météo
|
* Les Apis météo
|
||||||
* Système de requête
|
* Système de requête
|
||||||
|
|
||||||
Cette décomposition se traduit par la création de plusieurs interfaces et composants (et est visible sur le diagramme de classe) :
|
Cette décomposition se traduit par la création de plusieurs interfaces et composants (et est visible sur le diagramme de classe):
|
||||||
* WeatherDisplay pour l'affichage de telle sorte à avoir plusieurs affichages possibles
|
* WeatherDisplay pour l'affichage de tel sorte à avoir plusieurs affichages possibles
|
||||||
* WeatherDataApi pour l'implémentation des APIs standardisées grâce à l'objet WeatherData
|
* WeatherDataApi pour l'implémentation des Apis standardisées grâce à l'objet WeatherData
|
||||||
* JSONFetcher qui s'occupe de faire les requêtes aux APIs et permet par ce mécanisme de mock les tests en simulant la réponse d'un serveur api
|
* JSONFetcher qui s'occupe de faire les requêtes aux APIs et permet par ce mécanisme de mock les tests en simulant la réponse d'un serveur api
|
||||||
|
|
||||||
La mise en relation de ces différents composants sont possibles grâce au polymorphisme :
|
La mise en relation de ces différents composants sont possibles grâce au polymorphisme :
|
||||||
|
L'affichage utilise des instances de WeatherDataApi pour faire l'affichage mais on lui donne en réalité des implémentations des apis tel que OpenMeteo ou OpenWeatherMap
|
||||||
L'affichage utilise des instances de WeatherDataApi pour faire l'affichage, mais on lui donne en réalité des implémentations des APIs tel que OpenMeteo ou OpenWeatherMap.
|
|
||||||
|
|
||||||
En plus de cela, nous avons décidé d'abstraire d'autres parties du code pour déléguer certaines taches :
|
En plus de cela, nous avons décidé d'abstraire d'autres parties du code pour déléguer certaines taches :
|
||||||
* On utilise un type City dans nos implémentations d'APIs de sorte à abstraire la récupération des coordonnées GPS à partir d'un nom de ville (à l'aide de l'api du gouvernement).
|
* On utilise un type City dans nos implémentations d'apis de sorte à abstraire la récupération des coordonnées GPS à partir d'un nom de ville (à l'aide de l'api du gouvernement).
|
||||||
* Le JSONFetcher abstrait la partie requête HTTP(S) lors d'un appel à l'api. Il renvoie le résultat d'une requête sous forme d'un JSON.
|
* Le JSONFetcher abstrait la partie requête http(s) lors d'un appel à l'api. Il renvoit le résultat d'une requête sous forme d'un JSON.
|
||||||
|
|
||||||
Nous avons décidé d'ajouter un système de cache à l'implémentation de nos apis. C'est une fonctionnalité supplémentaire et pour ne pas avoir à changer toutes les implémentations d'APIs deux solutions s'offraient à nous :
|
Nous avons décidé d'ajouter un système de cache à l'implémentation de nos apis. C'est une fonctionnalité supplémentaire et pour ne pas avoir à changer toutes les implémentations d'apis deux solutions s'offraient à nous :
|
||||||
* Faire le cache au niveau du JSONFetcher :
|
* Faire le cache au niveau du JSONFetcher :
|
||||||
* Complétement transparent pour les implémentations (si une requête a déjà été faite, on renvoie la requête cachée)
|
* Complétement transparent pour les implémentations (si une requête a déjà été faite on renvoit la requête cachée)
|
||||||
* Mais couteuse en terme d'espace et ne permet pas de standardiser le stockage des données (ce que le sujet semble sous-entendre)
|
* Mais couteuse en terme d'espace et ne permet pas de standardiser le stockage des données (ce que le sujet semble sous entendre)
|
||||||
* Créer une classe abstraite ayant un système de cache intégré et ayant une méthode abstraite pour récupérer des données de type WeatherData
|
* Faire une Api de cache dont les autres implémentations hériteraient
|
||||||
|
|
||||||
Nous sommes partis sur la deuxième option, car elle demandait peu de modification sur le code existant. De plus, si on voit le paquet comme une bibliothèque, ce découpage permet simplement de laisser la liberté à l'utilisateur d'utiliser ou non un système de cache déjà codé.
|
|
||||||
|
|
||||||
|
Nous sommes partis sur la deuxième option.
|
||||||
|
Chaque implémentation souhaitant un système de cache hérite de la class abstraite WeatherDataCache et implémente simplement les fonctions de récupération de la météo comme si il n'y avait pas de cache.
|
||||||
C'est une solution simple et complète qui permet de gérer le cache efficacement.
|
C'est une solution simple et complète qui permet de gérer le cache efficacement.
|
||||||
|
|
||||||
Pour finir les exceptions qui peuvent être envoyées lors de requêtes aux APIs sont englobés dans une exception WeatherFetchingException.
|
Pour finir les exceptions qui peuvent être envoyées lors de requêtes aux apis sont englobés dans une exception WeatherFetchingException.
|
||||||
Il existe plusieurs variantes (qui hérite de cette exception mère) qui permettent d'avoir plus de détails sur le type d'exception (s'il s'agit d'un problème réseau, de la ville introuvable etc)
|
Il existe plusieurs variantes (qui hérite de cette exception mère) qui permettent d'avoir plus de détails sur le type d'exception (si il s'agit d'un problème réseau, de la ville introuvable etc)
|
||||||
Ces exceptions sont laissées à la charge de l'affichage qui décidera de la marche à suivre dans ces cas là.
|
Ces exceptions sont laissées à la charge de l'affichage qui décidera de la marche à suivre dans ces cas là.
|
||||||
|
|
||||||
-------------------------------------
|
-------------------------------------
|
||||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 48 KiB |
@ -1,130 +1 @@
|
|||||||
@startuml
|
@startuml
title Weather App
note "Getters, setters and constructors are not displayed" as N
package eirb.pg203 {
Interface WeatherDataAPI {
+ WeatherData getTemperature(int day, String city)
+ WeatherData getTemperature(int day, int hour, String city)
+ WeatherData getTemperatures(int days, String city)
+ String getAPIName()
}
Interface WeatherDisplay {
+ void display(int days, String city)
+ void addAPI(WeatherDataAPI w)
}
Exception exceptions.WeatherFeatchingException {
}
Exception exceptions.WeatherFeatchingExceptionApi extends exceptions.WeatherFeatchingException{
}
Exception exceptions.WeatherFeatchingExceptionCityCoords extends exceptions.WeatherFeatchingException{
}
Class utils.Coords {
- float lat
- float lon
}
Class utils.JSONFetcher {
+ fetch(URL url)
- private {static} fetchString(URL url)
}
Class City {
- String cityName
- utils.Coords cityCoords
~ JSONFetcher JSONFetcher
- private Coords getCoordsFromName(String cityName)
+ public String toString()
}
Class WeatherData {
- City city
- Instant date
- float temp
- Condition condition
- float windSpeed
- float windDirectionAngle
- WindDirection windDirection
+ String toString()
}
Class WeatherDisplayBasic implements WeatherDisplay {
- ArrayList<WeatherDataAPI> apis
- double getColumnSize()
- void displayHeader(int days, double sourceColumnSize, double dayColumnSize)
- void displayWeatherDatas(String apiName, ArrayList<WeatherData> weatherDatas, String startColumnSize, double sourceColumnSize, double dayColumnSize)
- void displaySeparatorLine(int days, double sourceColumnSize, double dayColumnSize)
- void displayAllWeatherDatas()
}
Class OpenMeteo implements WeatherDataAPI {
- String {final} forecastBaseUrl
- String {final} daylyQuery
~ JSONFetcher JSONFetcher
~ Clock clock
- JSONObject fetchWeather(int days, City city)
- Condition {static} getConditionFromCode(int WMOCode)
- WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city)
}
Class OpenWeatherMap implements WeatherDataAPI {
- String {static} forecastBaseUrl
- String APIKey
~ Clock clock
~ JSONFetcher JSONFetcher
- WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city)
- JSONObject fetchWeather(City city)
}
Class WeatherAPI implements WeatherDataAPI {
- String APIKey
- String {static} forecastBaseUrl
~ JSONFetcher JSONFetcher
- JSONObject fetchWeather(int days, String city)
- WeatherData.Condition {static} getConditionFromString(String str)
- WeatherData {static} getWeatherDataFromForecast(JSONObject response, int day, String city)
}
}
Exception Exception
Exception <|-- WeatherFeatchingException
@enduml
|
||||||
|
|
||||||
title Weather App
|
|
||||||
|
|
||||||
note "Getters, setters and constructors are not displayed" as N
|
|
||||||
|
|
||||||
package eirb.pg203.weather {
|
|
||||||
|
|
||||||
package data {
|
|
||||||
package api {
|
|
||||||
Interface WeatherDataAPI {
|
|
||||||
+ ArrayList<WeatherData> getTemperature(int day, String city)
|
|
||||||
+ ArrayList<WeatherData> getTemperature(int day, int hour, String city)
|
|
||||||
+ ArrayList<WeatherData> getTemperatures(int days, String city)
|
|
||||||
+ String getAPIName()
|
|
||||||
}
|
|
||||||
|
|
||||||
class WeatherDataCache {
|
|
||||||
- private HashMap<String,WeatherDataCache.CacheValue> cache
|
|
||||||
- private long cacheTTL
|
|
||||||
+ boolean has(String cityName, int day)
|
|
||||||
+ boolean needsUpdate(String cityName, int day)
|
|
||||||
+ void set(String cityName, int day, WeatherData value, Instant timestamp)
|
|
||||||
+ JSONArray toJSON(String apiName)
|
|
||||||
+ void fromJSON(JSONArray data)
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class WeatherCachedAPI implements WeatherDataAPI {
|
|
||||||
- private WeatherDataCache cache
|
|
||||||
+ JSONArray toJSON()
|
|
||||||
+ void loadCache(JSONArray data)
|
|
||||||
+ void loadCacheFromFile(String path)
|
|
||||||
+ void saveCacheToFile(String path)
|
|
||||||
+ ArrayList<WeatherData> getTemperature(JSONArray data)
|
|
||||||
}
|
|
||||||
|
|
||||||
Class OpenMeteo extends WeatherCachedAPI {
|
|
||||||
- String forecastBaseUrl
|
|
||||||
- String daylyQuery
|
|
||||||
~ JSONFetcher JSONFetcher
|
|
||||||
~ Clock clock
|
|
||||||
- JSONObject fetchWeather(int days, City city)
|
|
||||||
- Condition {static} getConditionFromCode(int WMOCode)
|
|
||||||
- ArrayList<WeatherData> getWeatherDataFromForecast(JSONObject response, int day, String city)
|
|
||||||
}
|
|
||||||
|
|
||||||
Class OpenWeatherMap extends WeatherCachedAPI {
|
|
||||||
- String {static} forecastBaseUrl
|
|
||||||
- String APIKey
|
|
||||||
~ Clock clock
|
|
||||||
~ JSONFetcher JSONFetcher
|
|
||||||
|
|
||||||
- WeatherData getWeatherDataFromForecast(JSONObject response, int day, String city)
|
|
||||||
- JSONObject fetchWeather(City city)
|
|
||||||
}
|
|
||||||
|
|
||||||
Class WeatherAPI extends WeatherCachedAPI {
|
|
||||||
- String APIKey
|
|
||||||
- String {static} forecastBaseUrl
|
|
||||||
~ JSONFetcher JSONFetcher
|
|
||||||
|
|
||||||
- JSONObject fetchWeather(int days, String city)
|
|
||||||
- WeatherData.Condition {static} getConditionFromString(String str)
|
|
||||||
- WeatherData {static} getWeatherDataFromForecast(JSONObject response, int day, String city)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Class WeatherData {
|
|
||||||
- City city
|
|
||||||
- Instant date
|
|
||||||
- float temp
|
|
||||||
- Condition condition
|
|
||||||
- float windSpeed
|
|
||||||
- float windDirectionAngle
|
|
||||||
- WindDirection windDirection
|
|
||||||
|
|
||||||
+ String toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
package display {
|
|
||||||
Class WeatherDisplayBasic implements WeatherDisplay {
|
|
||||||
- ArrayList<WeatherDataAPI> apis
|
|
||||||
|
|
||||||
- double getColumnSize()
|
|
||||||
- void displayHeader(int days, double sourceColumnSize, double dayColumnSize)
|
|
||||||
- void displayWeatherDatas(String apiName, ArrayList<WeatherData> weatherDatas, String startColumnSize, double sourceColumnSize, double dayColumnSize)
|
|
||||||
- void displaySeparatorLine(int days, double sourceColumnSize, double dayColumnSize)
|
|
||||||
- void displayAllWeatherDatas()
|
|
||||||
}
|
|
||||||
|
|
||||||
Interface WeatherDisplay {
|
|
||||||
+ void display(int days, String city)
|
|
||||||
+ void addAPI(WeatherDataAPI w)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
package exceptions {
|
|
||||||
Exception WeatherFeatchingException {}
|
|
||||||
Exception WeatherFeatchingExceptionApi extends WeatherFeatchingException{}
|
|
||||||
Exception WeatherFeatchingExceptionCityCoords extends WeatherFeatchingException{}
|
|
||||||
}
|
|
||||||
|
|
||||||
package utils {
|
|
||||||
Class utils.Coords {
|
|
||||||
- float lat
|
|
||||||
- float lon
|
|
||||||
}
|
|
||||||
|
|
||||||
Class utils.JSONFetcher {
|
|
||||||
+ fetch(URL url)
|
|
||||||
- private {static} fetchString(URL url)
|
|
||||||
}
|
|
||||||
|
|
||||||
Class City {
|
|
||||||
- String cityName
|
|
||||||
- utils.Coords cityCoords
|
|
||||||
~ JSONFetcher JSONFetcher
|
|
||||||
|
|
||||||
- private Coords getCoordsFromName(String cityName)
|
|
||||||
+ public String toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Exception Exception
|
|
||||||
Exception <|-- WeatherFeatchingException
|
|
||||||
WeatherDataCache "1" *-left- "1" WeatherCachedAPI
|
|
||||||
@enduml
|
|
@ -43,7 +43,7 @@ public class WeatherData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum WindDirection {
|
enum WindDirection {
|
||||||
N("🡩"),
|
N("🡩"),
|
||||||
NE("🡭"),
|
NE("🡭"),
|
||||||
E("🡪"),
|
E("🡪"),
|
||||||
@ -197,6 +197,7 @@ public class WeatherData {
|
|||||||
jsonObject.put("condition", condition.toString());
|
jsonObject.put("condition", condition.toString());
|
||||||
jsonObject.put("windSpeed", windSpeed);
|
jsonObject.put("windSpeed", windSpeed);
|
||||||
jsonObject.put("windDirectionAngle", windDirectionAngle);
|
jsonObject.put("windDirectionAngle", windDirectionAngle);
|
||||||
|
jsonObject.put("windDirection", windDirection.toString());
|
||||||
|
|
||||||
return jsonObject;
|
return jsonObject;
|
||||||
}
|
}
|
||||||
@ -207,7 +208,7 @@ public class WeatherData {
|
|||||||
float temp = data.getFloat("temp");
|
float temp = data.getFloat("temp");
|
||||||
float windSpeed = data.getFloat("windSpeed");
|
float windSpeed = data.getFloat("windSpeed");
|
||||||
float windDirectionAngle = data.getFloat("windDirectionAngle");
|
float windDirectionAngle = data.getFloat("windDirectionAngle");
|
||||||
Condition condition = Condition.fromString(data.getString("condition"));
|
Condition condition = Condition.fromString(data.getString("windDirection"));
|
||||||
|
|
||||||
return new WeatherData(city, date, temp, windSpeed, windDirectionAngle, condition);
|
return new WeatherData(city, date, temp, windSpeed, windDirectionAngle, condition);
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package eirb.pg203.weather.data.api;
|
|||||||
import eirb.pg203.weather.data.WeatherData;
|
import eirb.pg203.weather.data.WeatherData;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@ -11,9 +12,9 @@ import org.json.JSONObject;
|
|||||||
|
|
||||||
public class WeatherDataCache {
|
public class WeatherDataCache {
|
||||||
private static class CacheValue {
|
private static class CacheValue {
|
||||||
private final WeatherData value;
|
private WeatherData value;
|
||||||
private final int day;
|
private int day;
|
||||||
private final Instant timestamp;
|
private Instant timestamp;
|
||||||
|
|
||||||
CacheValue(WeatherData value, int day, Instant timestamp) {
|
CacheValue(WeatherData value, int day, Instant timestamp) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
@ -59,8 +60,8 @@ public class WeatherDataCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private final HashMap<String, CacheValue> cache = new HashMap<>();
|
private HashMap<String, CacheValue> cache = new HashMap<>();
|
||||||
private final long cacheTTL = 3600; // Cache data Time To Live in sec
|
private long cacheTTL = 3600; // Cache data Time To Live in sec
|
||||||
|
|
||||||
private String makeKey(String cityName, int day) {
|
private String makeKey(String cityName, int day) {
|
||||||
return String.format(Locale.ENGLISH, "%s%d", cityName, day);
|
return String.format(Locale.ENGLISH, "%s%d", cityName, day);
|
||||||
@ -86,7 +87,7 @@ public class WeatherDataCache {
|
|||||||
|
|
||||||
long dt = Instant.now().getEpochSecond() - cacheValue.getTimestamp().getEpochSecond();
|
long dt = Instant.now().getEpochSecond() - cacheValue.getTimestamp().getEpochSecond();
|
||||||
|
|
||||||
return dt > cacheTTL; // if older than TTL, needs update
|
return dt > this.cacheTTL; // if older than TTL, needs update
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
53
src/main/java/eirb/pg203/weather/utils/Cache.java
Normal file
53
src/main/java/eirb/pg203/weather/utils/Cache.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package eirb.pg203;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
class Cache {
|
||||||
|
HashMap<String, String> hashMap;
|
||||||
|
|
||||||
|
public Cache() {
|
||||||
|
this.hashMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean has(String key) {
|
||||||
|
return this.hashMap.get(key) == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String get(String key) {
|
||||||
|
return this.hashMap.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void set(String key, String value) {
|
||||||
|
this.hashMap.put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void flush() {
|
||||||
|
this.hashMap = new HashMap<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void fromString(String input) {
|
||||||
|
JSONArray data = new JSONArray(input);
|
||||||
|
|
||||||
|
for (int i = 0 ; i < data.length() ; ++i)
|
||||||
|
{
|
||||||
|
JSONObject entry = data.getJSONObject(i);
|
||||||
|
String key = entry.getString("key");
|
||||||
|
String value = entry.getString("value");
|
||||||
|
|
||||||
|
this.hashMap.put(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String exportString() {
|
||||||
|
JSONArray data = new JSONArray();
|
||||||
|
|
||||||
|
for (String key: this.hashMap.keySet())
|
||||||
|
data.put(this.hashMap.get(key));
|
||||||
|
|
||||||
|
return data.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,8 +1,6 @@
|
|||||||
package eirb.pg203.weather.data;
|
package eirb.pg203.weather.data;
|
||||||
|
|
||||||
import eirb.pg203.weather.utils.City;
|
import eirb.pg203.weather.utils.City;
|
||||||
|
|
||||||
import org.json.JSONObject;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
@ -50,46 +48,6 @@ public class WeatherDataTest {
|
|||||||
/* check if the setter works */
|
/* check if the setter works */
|
||||||
Assertions.assertEquals(condition, weatherData.getCondition());
|
Assertions.assertEquals(condition, weatherData.getCondition());
|
||||||
}
|
}
|
||||||
private static Stream<Arguments> conditionFromString() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.arguments("☀️", WeatherData.Condition.SUNNY),
|
|
||||||
Arguments.arguments("☁️", WeatherData.Condition.CLOUDY),
|
|
||||||
Arguments.arguments("🌤", WeatherData.Condition.PARTIAL),
|
|
||||||
Arguments.arguments("🌧", WeatherData.Condition.RAINY),
|
|
||||||
Arguments.arguments("E", WeatherData.Condition.ERROR)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "Condition {1} from string {0}")
|
|
||||||
@MethodSource
|
|
||||||
void conditionFromString(String conditionString, WeatherData.Condition expectedCondition) {
|
|
||||||
WeatherData.Condition condition = WeatherData.Condition.fromString(conditionString);
|
|
||||||
|
|
||||||
Assertions.assertEquals(expectedCondition, condition);
|
|
||||||
|
|
||||||
}
|
|
||||||
private static Stream<Arguments> windDirectionFromString() {
|
|
||||||
return Stream.of(
|
|
||||||
Arguments.arguments("🡩", WeatherData.WindDirection.N),
|
|
||||||
Arguments.arguments("🡭", WeatherData.WindDirection.NE),
|
|
||||||
Arguments.arguments("🡪", WeatherData.WindDirection.E),
|
|
||||||
Arguments.arguments("🡮", WeatherData.WindDirection.SE),
|
|
||||||
Arguments.arguments("🡫", WeatherData.WindDirection.S),
|
|
||||||
Arguments.arguments("🡯", WeatherData.WindDirection.SW),
|
|
||||||
Arguments.arguments("🡨", WeatherData.WindDirection.W),
|
|
||||||
Arguments.arguments("🡬", WeatherData.WindDirection.NW),
|
|
||||||
Arguments.arguments("E", WeatherData.WindDirection.ERROR),
|
|
||||||
Arguments.arguments("fjlkre", WeatherData.WindDirection.ERROR)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ParameterizedTest(name = "Wind direction {1} from string {0}")
|
|
||||||
@MethodSource
|
|
||||||
void windDirectionFromString(String windDirectionString, WeatherData.WindDirection expectedWindDirection) {
|
|
||||||
WeatherData.WindDirection windDirection = WeatherData.WindDirection.fromString(windDirectionString);
|
|
||||||
|
|
||||||
Assertions.assertEquals(expectedWindDirection, windDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void windSpeed() {
|
void windSpeed() {
|
||||||
@ -148,28 +106,4 @@ public class WeatherDataTest {
|
|||||||
weatherData.setWindDirectionAngle(windDirection);
|
weatherData.setWindDirectionAngle(windDirection);
|
||||||
Assertions.assertEquals(expectedWindDirection, weatherData.getWindDirection());
|
Assertions.assertEquals(expectedWindDirection, weatherData.getWindDirection());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
void toJSONTest() {
|
|
||||||
Instant now = Instant.now();
|
|
||||||
float temp = 0f;
|
|
||||||
WeatherData.Condition condition = WeatherData.Condition.SUNNY;
|
|
||||||
float windSpeed = 0f;
|
|
||||||
float windDirectionAngle = 0f;
|
|
||||||
WeatherData weatherData = new WeatherData(new City("aCity"), now, temp, windSpeed, windDirectionAngle, condition);
|
|
||||||
JSONObject equalsTo = new JSONObject();
|
|
||||||
|
|
||||||
equalsTo.put("city", "aCity");
|
|
||||||
equalsTo.put("date", now.toEpochMilli());
|
|
||||||
equalsTo.put("temp", temp);
|
|
||||||
equalsTo.put("condition", condition.toString());
|
|
||||||
equalsTo.put("windSpeed", windSpeed);
|
|
||||||
equalsTo.put("windDirectionAngle", windDirectionAngle);
|
|
||||||
|
|
||||||
Assertions.assertEquals(equalsTo.toString(), weatherData.toJSON().toString());
|
|
||||||
|
|
||||||
WeatherData weatherData2 = WeatherData.fromJSON(equalsTo);
|
|
||||||
|
|
||||||
Assertions.assertEquals(weatherData.toString(), weatherData2.toString());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,25 +0,0 @@
|
|||||||
package eirb.pg203.weather.utils;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
public class PairTest {
|
|
||||||
@Test
|
|
||||||
void pairGetTest() {
|
|
||||||
Pair<Integer, Integer> pair = new Pair<>(1, 2);
|
|
||||||
|
|
||||||
Assertions.assertEquals(1, pair.getKey());
|
|
||||||
Assertions.assertEquals(2, pair.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
void pairSetTest(){
|
|
||||||
Pair<Integer, Integer> pair = new Pair<>(1, 2);
|
|
||||||
|
|
||||||
pair.setKey(3);
|
|
||||||
pair.setValue(4);
|
|
||||||
Assertions.assertEquals(3, pair.getKey());
|
|
||||||
Assertions.assertEquals(4, pair.getValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
BIN
weather-app.png
Normal file
BIN
weather-app.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 159 KiB |
Loading…
x
Reference in New Issue
Block a user