feat: WeatherAPI tests

This commit is contained in:
Martin Eyben 2024-11-23 18:41:40 +01:00
parent 52e63be79c
commit e62635c057
10 changed files with 13425 additions and 43 deletions

View File

@ -19,7 +19,7 @@ import java.util.Locale;
*/
public class WeatherAPI implements WeatherDataAPI{
private final String weatherAPIKey;
private static final JSONFetcherInterface JSONFetcher = new JSONFetcher();
JSONFetcherInterface JSONFetcher = new JSONFetcher();
private static final String forecastBaseURL = "https://api.weatherapi.com/v1/forecast.json";
WeatherAPI(String weatherAPIKey) {

View File

@ -0,0 +1,43 @@
package eirb.pg203;
import eirb.pg203.utils.FileResourcesUtils;
import eirb.pg203.utils.JSONFetcherInterface;
import eirb.pg203.utils.SplitQueryUrl;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Map;
public class FakeJSONFetcherWeatherAPI implements JSONFetcherInterface {
private final static String baseUrlFormat = "https://api.weatherapi.com/v1/forecast.json?key=%s&q=%s&days=%d";
private final String apiKey = "realKey";
private static final JSONObject wrongKeyRequest = FileResourcesUtils.getFileFromResourceAsJson("WeatherAPI/wrong-apikey.json");
private static ArrayList<JSONObject> bordeauxRequests() {
ArrayList<JSONObject> bordeauxRequest = new ArrayList<>();
bordeauxRequest.add(FileResourcesUtils.getFileFromResourceAsJson("WeatherAPI/Bordeaux-1-partial.json"));
bordeauxRequest.add(FileResourcesUtils.getFileFromResourceAsJson("WeatherAPI/Bordeaux-2-partial-sunny.json"));
bordeauxRequest.add(FileResourcesUtils.getFileFromResourceAsJson("WeatherAPI/Bordeaux-3-partial-sunny-rain.json"));
bordeauxRequest.add(FileResourcesUtils.getFileFromResourceAsJson("WeatherAPI/Bordeaux-4-partial-sunny-rain-cloudy.json"));
return bordeauxRequest;
}
@Override
public JSONObject fetch(URL url) throws IOException {
Map<String, String> params = SplitQueryUrl.splitQuery(url);
int days = Integer.parseInt(params.get("days"));
if (!params.get("key").contentEquals(apiKey))
return wrongKeyRequest;
return bordeauxRequests().get(days - 1);
}
@Override
public JSONArray fetchArray(URL url) throws IOException {
return null;
}
}

View File

@ -2,70 +2,100 @@ package eirb.pg203;
import org.json.JSONObject;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import java.io.IOException;
import java.util.ArrayList;
import java.util.stream.Stream;
public class WeatherAPITest {
private static String APIKey = "cef8e1b6ea364994b5072423240111";
private static final String APIKey = "realKey";
private static final float epsilon = 0.01F;
private WeatherAPI weatherAPI;
@Test
public void testRightAPIKey() {
WeatherAPI weatherAPI = new WeatherAPI(WeatherAPITest.APIKey);
int day = 0;
// int hour = 10;
int days = 7;
String city = "Bordeaux";
@BeforeEach
public void setupWeatherApi() {
this.weatherAPI = new WeatherAPI(WeatherAPITest.APIKey);
this.weatherAPI.JSONFetcher = new FakeJSONFetcherWeatherAPI();
}
Assertions.assertAll(
() -> weatherAPI.getTemperature(day, city),
// () -> weatherAPI.getTemperature(day, hour, city),
() -> weatherAPI.getTemperatures(days, city)
/**
* List of args for Temperature testing
* @return Args for testing
*/
private static Stream<Arguments> testGetTemperature(){
return Stream.of(
Arguments.arguments(0, 8.1F,WeatherData.Condition.PARTIAL, 17.45F, 142.08F),
Arguments.arguments(1, 13F, WeatherData.Condition.SUNNY, 23.03F, 142.58F),
Arguments.arguments(2, 12.7F, WeatherData.Condition.RAINY, 13.19F, 222.92F),
Arguments.arguments(3, 8.1F,WeatherData.Condition.CLOUDY, 17.45F, 142.08F)
);
}
@Test
public void testWrongAPIKey() {
WeatherAPI weatherAPI = new WeatherAPI("");
int day = 0;
// int hour = 10;
int days = 7;
@ParameterizedTest(name="Temperature fetch at Bordeaux D+{0}")
@MethodSource
public void testGetTemperature(int day, float expectedTemp, WeatherData.Condition expectedCond, float expectedWindSpeed, float expectedWindAngle) throws IOException {
String city = "Bordeaux";
WeatherData weatherData;
weatherData = weatherAPI.getTemperature(day, city);
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperature(day, city));
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperatures(days, city));
/* Temperatures */
Assertions.assertEquals(expectedTemp, weatherData.getTemp());
/* Condition */
Assertions.assertEquals(expectedCond, weatherData.getCondition());
/* Wind */
Assertions.assertTrue(expectedWindSpeed - weatherData.getWindSpeed() < epsilon);
Assertions.assertTrue(expectedWindAngle - weatherData.getWindDirectionAngle() < epsilon);
}
/**
* For coverage (hour not yet implemented)
* @throws IOException never
*/
@Test
public void testWrongDay() {
WeatherAPI weatherAPI = new WeatherAPI(WeatherAPITest.APIKey);
public void testGetTemperatureByHour() throws IOException {
String city = "Bordeaux";
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperature(-1, city));
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperature(15, city));
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperatures(15, city));
Assertions.assertThrows(IOException.class, () -> weatherAPI.getTemperatures(-1, city));
}
@Test
public void testRightDay() {
WeatherAPI weatherAPI = new WeatherAPI(WeatherAPITest.APIKey);
String city = "Bordeaux";
Assertions.assertAll(
() -> weatherAPI.getTemperature(0, city),
() -> weatherAPI.getTemperature(5, city),
() -> weatherAPI.getTemperature(14, city),
() -> weatherAPI.getTemperatures(0, city),
() -> weatherAPI.getTemperatures(8, city),
() -> weatherAPI.getTemperatures(14, city)
() -> weatherAPI.getTemperature(0,1, city)
);
}
@Test
@DisplayName("Multiple day temperature fetch")
public void testGetTemperatures() throws IOException {
String city = "Bordeaux";
int days = 3;
float[] expectedTemperatures = {8.1F, 13F, 12.7F, 8.1F};
WeatherData.Condition[] expectedConditions = {WeatherData.Condition.PARTIAL, WeatherData.Condition.SUNNY, WeatherData.Condition.RAINY, WeatherData.Condition.CLOUDY};
float[] expectedWindSpeed = {17.45F, 23.03F, 13.19F, 17.45F};
float[] expectedWindDirection = {142.08F, 142.58F, 222.92F, 142.08F};
ArrayList<WeatherData> weatherDatas;
WeatherData weatherData;
weatherDatas = weatherAPI.getTemperatures(days, city);
for (int index = 0; index < days; index++) {
weatherData = weatherDatas.get(index);
/* Temperatures */
Assertions.assertEquals(expectedTemperatures[index], weatherData.getTemp());
/* Weather condition */
Assertions.assertEquals(expectedConditions[index], weatherData.getCondition());
/* Wind */
Assertions.assertTrue(expectedWindSpeed[index] - weatherData.getWindSpeed() < epsilon);
Assertions.assertTrue(expectedWindDirection[index] - weatherData.getWindDirectionAngle() < epsilon);
}
}
@Test
public void testGetAPIName() {
WeatherAPI weatherAPI = new WeatherAPI(WeatherAPITest.APIKey);
Assertions.assertTrue(weatherAPI.getAPIName().equals("WeatherAPI"));
Assertions.assertEquals("WeatherAPI", weatherAPI.getAPIName());
}
}

View File

@ -0,0 +1,53 @@
package eirb.pg203.utils;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class FileResourcesUtils {
/**
* Fetch ressource file
* Code from https://mkyong.com
* @param fileName
* @return
*/
public static InputStream getFileFromResourceAsStream(String fileName) {
// The class loader that loaded the class
ClassLoader classLoader = FileResourcesUtils.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream(fileName);
// the stream holding the file content
if (inputStream == null) {
throw new IllegalArgumentException("file not found! " + fileName);
} else {
return inputStream;
}
}
public static JSONObject getFileFromResourceAsJson(String fileName) {
InputStream inputStream = getFileFromResourceAsStream(fileName);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line;
while(true){
try {
if (!bufferedReader.ready()) break;
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
line = bufferedReader.readLine();
} catch (IOException e) {
throw new RuntimeException(e);
}
stringBuilder.append(line);
}
return new JSONObject(stringBuilder.toString());
}
}

View File

@ -0,0 +1,20 @@
package eirb.pg203.utils;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.LinkedHashMap;
import java.util.Map;
public class SplitQueryUrl {
public static Map<String, String> splitQuery(URL url) throws UnsupportedEncodingException {
Map<String, String> query_pairs = new LinkedHashMap<String, String>();
String query = url.getQuery();
String[] pairs = query.split("&");
for (String pair : pairs) {
int idx = pair.indexOf("=");
query_pairs.put(URLDecoder.decode(pair.substring(0, idx), "UTF-8"), URLDecoder.decode(pair.substring(idx + 1), "UTF-8"));
}
return query_pairs;
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,6 @@
{
"error": {
"code": 2008,
"message": "API key has been disabled."
}
}