From 830eafd2cedb61f14a6bccc47471a0d7210c5337 Mon Sep 17 00:00:00 2001 From: Christopher Bohn <bohn@unl.edu> Date: Fri, 12 Nov 2021 15:44:41 -0600 Subject: [PATCH] Reformatted to SOFT160 formatting specification --- pom.xml | 93 +- .../json_connections/Demonstration.java | 549 +- .../connection/Connection.java | 20 +- .../connection/FileConnection.java | 93 +- .../connection/RestConnection.java | 142 +- .../connector/OpenWeatherConnector.java | 3420 +++++++----- .../AirPollution_UnlNov24ToNov27Test.java | 147 +- .../AirPollution_WebsiteExampleTest.java | 174 +- .../json_connections/ExceptionsTest.java | 4790 ++++++++--------- .../Forecast_UnlNov7ToNov12Test.java | 205 +- .../OneCall_WebsiteExampleTest.java | 495 +- .../Weather_UnlOct24At0917Test.java | 180 +- .../Weather_WebsiteExampleTest.java | 167 +- 13 files changed, 5459 insertions(+), 5016 deletions(-) diff --git a/pom.xml b/pom.xml index e9f0333..7cf766f 100644 --- a/pom.xml +++ b/pom.xml @@ -1,50 +1,51 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> - <modelVersion>4.0.0</modelVersion> - <groupId>edu.unl.cse.soft160.rest_connector</groupId> - <artifactId>rest_and_file_connector</artifactId> - <packaging>jar</packaging> - <version>1.0-SNAPSHOT</version> - <name>rest_connector</name> - <url>http://maven.apache.org</url> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> + <modelVersion>4.0.0</modelVersion> + <groupId>edu.unl.cse.soft160.rest_connector</groupId> + <artifactId>rest_and_file_connector</artifactId> + <packaging>jar</packaging> + <version>1.0-SNAPSHOT</version> + <name>rest_connector</name> + <url>http://maven.apache.org</url> - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - </properties> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> - <build> - <plugins> - <plugin> - <artifactId>maven-compiler-plugin</artifactId> - <version>3.8.1</version> - <configuration> - <source>11</source> - <target>11</target> - </configuration> - </plugin> - <plugin> - <groupId>org.apache.maven.plugins</groupId> - <artifactId>maven-javadoc-plugin</artifactId> - <version>3.3.1</version> - <configuration> - <show>public</show> - <source>11</source> - </configuration> - </plugin> - </plugins> - </build> + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> + <configuration> + <source>11</source> + <target>11</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-javadoc-plugin</artifactId> + <version>3.3.1</version> + <configuration> + <show>public</show> + <source>11</source> + </configuration> + </plugin> + </plugins> + </build> - <dependencies> - <dependency> - <groupId>com.googlecode.json-simple</groupId> - <artifactId>json-simple</artifactId> - <version>1.1.1</version> - </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.13</version> - <scope>test</scope> - </dependency> - </dependencies> + <dependencies> + <dependency> + <groupId>com.googlecode.json-simple</groupId> + <artifactId>json-simple</artifactId> + <version>1.1.1</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13</version> + <scope>test</scope> + </dependency> + </dependencies> </project> diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java b/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java index e2a7bae..4148324 100644 --- a/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java +++ b/src/main/java/edu/unl/cse/soft160/json_connections/Demonstration.java @@ -16,291 +16,290 @@ import java.util.List; import java.util.Scanner; public class Demonstration { - private static String getDataSet(Scanner scanner) { - List<String> dataSets = new ArrayList<>(OpenWeatherConnector.allowableDataSets); - for (int i = 0; i < dataSets.size(); ++i) { - System.out.println((i + 1) + ". " + dataSets.get(i)); - } - System.out.print(System.lineSeparator() + "Please enter the desired data set: "); - int choice = scanner.nextInt(); - scanner.nextLine(); + private static String getDataSet(Scanner scanner) { + List<String> dataSets = new ArrayList<>(OpenWeatherConnector.allowableDataSets); + for (int i = 0; i < dataSets.size(); ++i) { + System.out.println((i + 1) + ". " + dataSets.get(i)); + } + System.out.print(System.lineSeparator() + "Please enter the desired data set: "); + int choice = scanner.nextInt(); + scanner.nextLine(); - return dataSets.get(choice - 1); - } + return dataSets.get(choice - 1); + } - private static String getData(OpenWeatherConnector weather, String dataSet, Instant now, Scanner scanner) { - String query; - switch (dataSet) { - case "weather": - case "forecast": - query = "zip=68588"; - break; - case "onecall": - case "air_pollution": - case "air_pollution/forecast": - query = "lat=40.81506358&lon=-96.7048613"; - break; - case "air_pollution/history": - Instant yesterday = now.minus(1, ChronoUnit.DAYS); - Instant twoDaysAgo = now.minus(2, ChronoUnit.DAYS); - query = "lat=40.81506358&lon=-96.7048613&start=" + - twoDaysAgo.getEpochSecond() + "&end=" + yesterday.getEpochSecond(); - break; - default: - System.err.println("The " + dataSet + " dataset is not currently supported."); - query = ""; - } + private static String getData(OpenWeatherConnector weather, String dataSet, Instant now, Scanner scanner) { + String query; + switch (dataSet) { + case "weather": + case "forecast": + query = "zip=68588"; + break; + case "onecall": + case "air_pollution": + case "air_pollution/forecast": + query = "lat=40.81506358&lon=-96.7048613"; + break; + case "air_pollution/history": + Instant yesterday = now.minus(1, ChronoUnit.DAYS); + Instant twoDaysAgo = now.minus(2, ChronoUnit.DAYS); + query = "lat=40.81506358&lon=-96.7048613&start=" + twoDaysAgo.getEpochSecond() + "&end=" + + yesterday.getEpochSecond(); + break; + default: + System.err.println("The " + dataSet + " dataset is not currently supported."); + query = ""; + } - if (!query.equals("")) { - System.out.print("Enter query, or press the ENTER key to accept the example query (" + query + "): "); - String userQuery = scanner.nextLine(); - if(!userQuery.equals("")) { - System.out.println(" " + "*".repeat(76)); - System.out.println(" *** The following example output strings assume default units. ***"); - System.out.println(" *** If you specified other units, the values will be correct, but ***"); - System.out.println(" *** the stated units will be the defaults, not your specified units. ***"); - System.out.println(" " + "*".repeat(76)); - query = userQuery; - } - } + if (!query.equals("")) { + System.out.print("Enter query, or press the ENTER key to accept the example query (" + query + "): "); + String userQuery = scanner.nextLine(); + if (!userQuery.equals("")) { + System.out.println(" " + "*".repeat(76)); + System.out.println(" *** The following example output strings assume default units. ***"); + System.out.println(" *** If you specified other units, the values will be correct, but ***"); + System.out.println(" *** the stated units will be the defaults, not your specified units. ***"); + System.out.println(" " + "*".repeat(76)); + query = userQuery; + } + } - String data = null; - if (!query.equals("")) { - System.out.println("Requesting data at " + now); - try { - data = weather.retrieveData(query); - } catch (IOException ioException) { - System.err.println("IO Exception: " + ioException.getClass()); - System.err.println("\t" + ioException.getMessage()); - System.err.println("Caused by: " + ioException.getCause()); - if (ioException.getCause() != null) { - System.err.println("\t" + ioException.getCause().getMessage()); - } - } - } else { - System.err.println("Not requesting data at " + now + " due to empty query."); - } - return data; - } + String data = null; + if (!query.equals("")) { + System.out.println("Requesting data at " + now); + try { + data = weather.retrieveData(query); + } catch (IOException ioException) { + System.err.println("IO Exception: " + ioException.getClass()); + System.err.println("\t" + ioException.getMessage()); + System.err.println("Caused by: " + ioException.getCause()); + if (ioException.getCause() != null) { + System.err.println("\t" + ioException.getCause().getMessage()); + } + } + } else { + System.err.println("Not requesting data at " + now + " due to empty query."); + } + return data; + } - private static void optionallySaveDataToFile(String data, String dataSet, Scanner scanner) { - System.out.print(System.lineSeparator() + "Do you wish to save this data to a file Y/(N)? "); - String answer = scanner.nextLine(); - if (answer.length() > 0 && answer.toUpperCase().charAt(0) == 'Y') { - System.out.print("What shall the file's name be? "); - String filename = scanner.nextLine(); - if (!filename.endsWith(".json")) { - filename += ".json"; - } - FileConnection fileConnection = new FileConnection(dataSet); - try { - System.out.println("Saving..."); - fileConnection.save(filename, (JSONObject)new JSONParser().parse(data)); - System.out.println("\t" + filename + " saved"); - } catch (ParseException | IOException exception) { - exception.printStackTrace(); - } - } else { - System.out.println("Not saving data."); - } - } - - private static void reportAirPollutionHistoryOrForecastData(OpenWeatherConnector weather, Instant now) { - Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2); - System.out.println("The air quality at " + timestamp + - (timestamp.toInstant().isBefore(now) ? " was " : " will be ") + - weather.getAirQualityIndex(timestamp) + " pollutant concentration"); - System.out.println("CO: " + weather.getCarbonMonoxide(timestamp) + " μg/m3"); - System.out.println("NO: " + weather.getNitrogenMonoxide(timestamp) + " μg/m3"); - System.out.println("NO2: " + weather.getNitrogenDioxide(timestamp) + " μg/m3"); - System.out.println("O3: " + weather.getOzone(timestamp) + " μg/m3"); - System.out.println("SO2: " + weather.getSulfurDioxide(timestamp) + " μg/m3"); - System.out.println("NH3: " + weather.getAmmonia(timestamp) + " μg/m3"); - System.out.println("Fine particulate matter: " + weather.getFineParticulateMatter(timestamp) + " " + - "μg/m3"); - System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter(timestamp) + " " + - "μg/m3"); - } + private static void optionallySaveDataToFile(String data, String dataSet, Scanner scanner) { + System.out.print(System.lineSeparator() + "Do you wish to save this data to a file Y/(N)? "); + String answer = scanner.nextLine(); + if (answer.length() > 0 && answer.toUpperCase().charAt(0) == 'Y') { + System.out.print("What shall the file's name be? "); + String filename = scanner.nextLine(); + if (!filename.endsWith(".json")) { + filename += ".json"; + } + FileConnection fileConnection = new FileConnection(dataSet); + try { + System.out.println("Saving..."); + fileConnection.save(filename, (JSONObject) new JSONParser().parse(data)); + System.out.println("\t" + filename + " saved"); + } catch (ParseException | IOException exception) { + exception.printStackTrace(); + } + } else { + System.out.println("Not saving data."); + } + } - private static void reportAirPollutionData(OpenWeatherConnector weather) { - System.out.println("The current air quality is " + weather.getAirQualityIndex() + - " pollutant concentration"); - System.out.println("CO: " + weather.getCarbonMonoxide() + " μg/m3"); - System.out.println("NO: " + weather.getNitrogenMonoxide() + " μg/m3"); - System.out.println("NO2: " + weather.getNitrogenDioxide() + " μg/m3"); - System.out.println("O3: " + weather.getOzone() + " μg/m3"); - System.out.println("SO2: " + weather.getSulfurDioxide() + " μg/m3"); - System.out.println("NH3: " + weather.getAmmonia() + " μg/m3"); - System.out.println("Fine particulate matter: " + weather.getFineParticulateMatter() + " μg/m3"); - System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter() + " μg/m3"); - } + private static void reportAirPollutionHistoryOrForecastData(OpenWeatherConnector weather, Instant now) { + Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2); + System.out.println( + "The air quality at " + timestamp + (timestamp.toInstant().isBefore(now) ? " was " : " will be ") + + weather.getAirQualityIndex(timestamp) + " pollutant concentration"); + System.out.println("CO: " + weather.getCarbonMonoxide(timestamp) + " μg/m3"); + System.out.println("NO: " + weather.getNitrogenMonoxide(timestamp) + " μg/m3"); + System.out.println("NO2: " + weather.getNitrogenDioxide(timestamp) + " μg/m3"); + System.out.println("O3: " + weather.getOzone(timestamp) + " μg/m3"); + System.out.println("SO2: " + weather.getSulfurDioxide(timestamp) + " μg/m3"); + System.out.println("NH3: " + weather.getAmmonia(timestamp) + " μg/m3"); + System.out.println("Fine particulate matter: " + weather.getFineParticulateMatter(timestamp) + " " + "μg/m3"); + System.out + .println("Coarse particulate matter: " + weather.getCoarseParticulateMatter(timestamp) + " " + "μg/m3"); + } - private static void reportOneCallData(OpenWeatherConnector weather) { - Date timestamp; - System.out.println("It is currently " + weather.getWeatherCategories()); - System.out.println("Specifically, it is " + weather.getWeatherDescriptions()); - System.out.println("The temperature is " + weather.getTemperature() + "K"); - System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, the dew " + - "point is " + weather.getDewPoint() + "K, and it feels like " + weather.getFeelsLike() + "K"); - System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" + - " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s"); - System.out.println("Visibility is " + weather.getVisibility() + "m"); - System.out.println("The pressure is " + weather.getPressure() + "hPa"); - System.out.println("Cloud cover is " + weather.getCloudCover() + "%"); - System.out.println("The UV Index is " + weather.getUltravioletIndex()); - System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" + - " rain and " + weather.getOneHourSnowfall() + "mm of snow."); - if (weather.getTimestamps("minutely").size() > 0) { - System.out.println("There is minutely data from " + weather.getTimestamps("minutely").get(0) + " to " + - weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() - 1)); - timestamp = weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() / 2); - System.out.println("\tAt " + timestamp + " the 1-hour (?) precipitation total will be " + - weather.getMinutelyPrecipitation(timestamp)); - } else { - System.out.println("There is no minutely data."); - } - if (weather.getTimestamps("hourly").size() > 0) { - System.out.println("There is hourly data from " + weather.getTimestamps("hourly").get(0) + " to " + - weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() - 1)); - timestamp = weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() / 2); - System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); - System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp)); - System.out.println("\tThe temperature will be " + weather.getTemperature(timestamp) + "K"); - System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, the dew " + - "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like " + - weather.getFeelsLike(timestamp) + "K"); - System.out.println("\tThat probably also factored in winds, which will be " + - weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) + - "˚, gusting to " + weather.getWindGust(timestamp) + "m/s"); - System.out.println("\tVisibility will be " + weather.getVisibility(timestamp) + "m"); - System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa"); - System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%"); - System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp)); - System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + - "chance of precipitation, resulting in " + weather.getOneHourRainfall(timestamp) + "mm of " + - "rain and " + weather.getOneHourSnowfall(timestamp) + "mm of snow in the hour before " + - timestamp); - } else { - System.out.println("There is no hourly data."); - } - if (weather.getTimestamps("daily").size() > 0) { - System.out.println("There is daily data from " + weather.getTimestamps("daily").get(0) + " to " + - weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() - 1)); - timestamp = weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() / 2); - System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); - System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp)); - System.out.println("\tThe temperatures will range from " + weather.getLowTemperature(timestamp) + "K to " + - weather.getHighTemperature(timestamp) + "K"); - System.out.println("\t\tMorning:" + weather.getMorningTemperature(timestamp) + "K"); - System.out.println("\t\tDaytime:" + weather.getDaytimeTemperature(timestamp) + "K"); - System.out.println("\t\tEvening:" + weather.getEveningTemperature(timestamp) + "K"); - System.out.println("\t\tNighttime:" + weather.getNighttimeTemperature(timestamp) + "K"); - System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, the dew " + - "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like:"); - System.out.println("\t\tMorning:" + weather.getMorningFeelsLike(timestamp) + "K"); - System.out.println("\t\tDaytime:" + weather.getDaytimeFeelsLike(timestamp) + "K"); - System.out.println("\t\tEvening:" + weather.getEveningFeelsLike(timestamp) + "K"); - System.out.println("\t\tNighttime:" + weather.getNighttimeFeelsLike(timestamp) + "K"); - System.out.println("\tThat probably also factored in winds, which will be " + - weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) + - "˚, gusting to " + weather.getWindGust(timestamp) + "m/s"); - System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa"); - System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%"); - System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp)); - System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + - "chance of precipitation, resulting in " + weather.getDailyRainfall(timestamp) + "mm of " + - "rain and " + weather.getDailySnowfall(timestamp) + "mm of snow"); - } else { - System.out.println("There is no daily data."); - } - } + private static void reportAirPollutionData(OpenWeatherConnector weather) { + System.out.println("The current air quality is " + weather.getAirQualityIndex() + " pollutant concentration"); + System.out.println("CO: " + weather.getCarbonMonoxide() + " μg/m3"); + System.out.println("NO: " + weather.getNitrogenMonoxide() + " μg/m3"); + System.out.println("NO2: " + weather.getNitrogenDioxide() + " μg/m3"); + System.out.println("O3: " + weather.getOzone() + " μg/m3"); + System.out.println("SO2: " + weather.getSulfurDioxide() + " μg/m3"); + System.out.println("NH3: " + weather.getAmmonia() + " μg/m3"); + System.out.println("Fine particulate matter: " + weather.getFineParticulateMatter() + " μg/m3"); + System.out.println("Coarse particulate matter: " + weather.getCoarseParticulateMatter() + " μg/m3"); + } - private static void reportForecastData(OpenWeatherConnector weather) { - Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2); - System.out.println("At " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); - System.out.println("Specifically, it will be " + weather.getWeatherDescriptions(timestamp)); - System.out.println("The temperature will be " + weather.getTemperature(timestamp) + "K"); - System.out.println("Factoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, " + - "it will feel like " + weather.getFeelsLike(timestamp) + "K"); - System.out.println("That probably also factored in winds, which will be " + - weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) + - "˚, gusting to " + weather.getWindGust(timestamp) + "m/s"); - System.out.println("Visibility will be " + weather.getVisibility(timestamp) + "m"); - System.out.println("The pressure will be " + weather.getPressure(timestamp) + "hPa"); - System.out.println("Cloud cover will be " + weather.getCloudCover(timestamp) + "%"); - System.out.println("There will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + - "chance of precipitation, resulting in " + weather.getThreeHourRainfall(timestamp) + "mm of " + - "rain and " + weather.getThreeHourSnowfall(timestamp) + "mm of snow in the three hours before" + - " " + timestamp); - } + private static void reportOneCallData(OpenWeatherConnector weather) { + Date timestamp; + System.out.println("It is currently " + weather.getWeatherCategories()); + System.out.println("Specifically, it is " + weather.getWeatherDescriptions()); + System.out.println("The temperature is " + weather.getTemperature() + "K"); + System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, the dew " + + "point is " + weather.getDewPoint() + "K, and it feels like " + weather.getFeelsLike() + "K"); + System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" + + " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s"); + System.out.println("Visibility is " + weather.getVisibility() + "m"); + System.out.println("The pressure is " + weather.getPressure() + "hPa"); + System.out.println("Cloud cover is " + weather.getCloudCover() + "%"); + System.out.println("The UV Index is " + weather.getUltravioletIndex()); + System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" + + " rain and " + weather.getOneHourSnowfall() + "mm of snow."); + if (weather.getTimestamps("minutely").size() > 0) { + System.out.println("There is minutely data from " + weather.getTimestamps("minutely").get(0) + " to " + + weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() - 1)); + timestamp = weather.getTimestamps("minutely").get(weather.getTimestamps("minutely").size() / 2); + System.out.println("\tAt " + timestamp + " the 1-hour (?) precipitation total will be " + + weather.getMinutelyPrecipitation(timestamp)); + } else { + System.out.println("There is no minutely data."); + } + if (weather.getTimestamps("hourly").size() > 0) { + System.out.println("There is hourly data from " + weather.getTimestamps("hourly").get(0) + " to " + + weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() - 1)); + timestamp = weather.getTimestamps("hourly").get(weather.getTimestamps("hourly").size() / 2); + System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); + System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp)); + System.out.println("\tThe temperature will be " + weather.getTemperature(timestamp) + "K"); + System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + + "%, the dew " + "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like " + + weather.getFeelsLike(timestamp) + "K"); + System.out.println("\tThat probably also factored in winds, which will be " + + weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) + + "˚, gusting to " + weather.getWindGust(timestamp) + "m/s"); + System.out.println("\tVisibility will be " + weather.getVisibility(timestamp) + "m"); + System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa"); + System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%"); + System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp)); + System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + + "chance of precipitation, resulting in " + weather.getOneHourRainfall(timestamp) + "mm of " + + "rain and " + weather.getOneHourSnowfall(timestamp) + "mm of snow in the hour before " + + timestamp); + } else { + System.out.println("There is no hourly data."); + } + if (weather.getTimestamps("daily").size() > 0) { + System.out.println("There is daily data from " + weather.getTimestamps("daily").get(0) + " to " + + weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() - 1)); + timestamp = weather.getTimestamps("daily").get(weather.getTimestamps("daily").size() / 2); + System.out.println("\tAt " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); + System.out.println("\tSpecifically, it will be " + weather.getWeatherDescriptions(timestamp)); + System.out.println("\tThe temperatures will range from " + weather.getLowTemperature(timestamp) + "K to " + + weather.getHighTemperature(timestamp) + "K"); + System.out.println("\t\tMorning:" + weather.getMorningTemperature(timestamp) + "K"); + System.out.println("\t\tDaytime:" + weather.getDaytimeTemperature(timestamp) + "K"); + System.out.println("\t\tEvening:" + weather.getEveningTemperature(timestamp) + "K"); + System.out.println("\t\tNighttime:" + weather.getNighttimeTemperature(timestamp) + "K"); + System.out.println("\tFactoring in the relative humidity of " + weather.getHumidity(timestamp) + + "%, the dew " + "point will be " + weather.getDewPoint(timestamp) + "K, and it will feel like:"); + System.out.println("\t\tMorning:" + weather.getMorningFeelsLike(timestamp) + "K"); + System.out.println("\t\tDaytime:" + weather.getDaytimeFeelsLike(timestamp) + "K"); + System.out.println("\t\tEvening:" + weather.getEveningFeelsLike(timestamp) + "K"); + System.out.println("\t\tNighttime:" + weather.getNighttimeFeelsLike(timestamp) + "K"); + System.out.println("\tThat probably also factored in winds, which will be " + + weather.getWindSpeed(timestamp) + "m/s from " + weather.getWindDirection(timestamp) + + "˚, gusting to " + weather.getWindGust(timestamp) + "m/s"); + System.out.println("\tThe pressure will be " + weather.getPressure(timestamp) + "hPa"); + System.out.println("\tCloud cover will be " + weather.getCloudCover(timestamp) + "%"); + System.out.println("\tThe UV Index will be " + weather.getUltravioletIndex(timestamp)); + System.out.println("\tThere will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + + "chance of precipitation, resulting in " + weather.getDailyRainfall(timestamp) + "mm of " + + "rain and " + weather.getDailySnowfall(timestamp) + "mm of snow"); + } else { + System.out.println("There is no daily data."); + } + } - private static void reportWeatherData(OpenWeatherConnector weather) { - System.out.println("It is currently " + weather.getWeatherCategories()); - System.out.println("Specifically, it is " + weather.getWeatherDescriptions()); - System.out.println("The temperature is " + weather.getTemperature() + "K"); - System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, it feels " + - "like " + weather.getFeelsLike() + "K"); - System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" + - " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s"); - System.out.println("Visibility is " + weather.getVisibility() + "m"); - System.out.println("The pressure is " + weather.getPressure() + "hPa"); - System.out.println("Cloud cover is " + weather.getCloudCover() + "%"); - System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" + - " rain and " + weather.getOneHourSnowfall() + "mm of snow."); - System.out.println("If three-hour precipitation data is reported, it's " + - weather.getThreeHourRainfall() + "mm of rain and " + weather.getThreeHourSnowfall() + "mm of " + - "snow. (You might not want to trust those values if they match the 1-hour precipitation.)"); - } - - public static void main(String... args) { - Scanner scanner = new Scanner(System.in); - Instant now = Instant.now(); - String apiKey = null; - try { - apiKey = RestConnection.getApiKey("openweathermap"); - } catch (IOException ioException) { - System.err.println("IO Exception: " + ioException.getClass()); - System.err.println("\t" + ioException.getMessage()); - System.err.println("Caused by: " + ioException.getCause()); - System.err.println("\t" + ioException.getCause().getMessage()); - } + private static void reportForecastData(OpenWeatherConnector weather) { + Date timestamp = weather.getTimestamps().get(weather.getTimestamps().size() / 2); + System.out.println("At " + timestamp + " it will be " + weather.getWeatherCategories(timestamp)); + System.out.println("Specifically, it will be " + weather.getWeatherDescriptions(timestamp)); + System.out.println("The temperature will be " + weather.getTemperature(timestamp) + "K"); + System.out.println("Factoring in the relative humidity of " + weather.getHumidity(timestamp) + "%, " + + "it will feel like " + weather.getFeelsLike(timestamp) + "K"); + System.out.println("That probably also factored in winds, which will be " + weather.getWindSpeed(timestamp) + + "m/s from " + weather.getWindDirection(timestamp) + "˚, gusting to " + weather.getWindGust(timestamp) + + "m/s"); + System.out.println("Visibility will be " + weather.getVisibility(timestamp) + "m"); + System.out.println("The pressure will be " + weather.getPressure(timestamp) + "hPa"); + System.out.println("Cloud cover will be " + weather.getCloudCover(timestamp) + "%"); + System.out.println("There will be a " + weather.getProbabilityOfPrecipitation(timestamp) * 100 + "% " + + "chance of precipitation, resulting in " + weather.getThreeHourRainfall(timestamp) + "mm of " + + "rain and " + weather.getThreeHourSnowfall(timestamp) + "mm of snow in the three hours before" + " " + + timestamp); + } - String dataSet = getDataSet(scanner); - OpenWeatherConnector weather = new OpenWeatherConnector(dataSet, apiKey); - String data = getData(weather, dataSet, now, scanner); - - System.out.println("Raw JSON: " + data); - if (data != null) { - System.out.println("Location: " + weather.getLatitude() + " latitude, " + weather.getLongitude() + " " + - "longitude"); - Date currentTimeStamp = weather.getTimestamp(); - System.out.println("Current timestamp: " + - (currentTimeStamp == OpenWeatherConnector.IMPOSSIBLE_DATE ? "not present" : currentTimeStamp)); - System.out.println("Available timestamps: " + weather.getTimestamps()); + private static void reportWeatherData(OpenWeatherConnector weather) { + System.out.println("It is currently " + weather.getWeatherCategories()); + System.out.println("Specifically, it is " + weather.getWeatherDescriptions()); + System.out.println("The temperature is " + weather.getTemperature() + "K"); + System.out.println("Factoring in the relative humidity of " + weather.getHumidity() + "%, it feels " + "like " + + weather.getFeelsLike() + "K"); + System.out.println("That probably also factored in winds, which are " + weather.getWindSpeed() + "m/s" + + " from " + weather.getWindDirection() + "˚, gusting to " + weather.getWindGust() + "m/s"); + System.out.println("Visibility is " + weather.getVisibility() + "m"); + System.out.println("The pressure is " + weather.getPressure() + "hPa"); + System.out.println("Cloud cover is " + weather.getCloudCover() + "%"); + System.out.println("Precipitation in the last hour has been " + weather.getOneHourRainfall() + "mm of" + + " rain and " + weather.getOneHourSnowfall() + "mm of snow."); + System.out.println("If three-hour precipitation data is reported, it's " + weather.getThreeHourRainfall() + + "mm of rain and " + weather.getThreeHourSnowfall() + "mm of " + + "snow. (You might not want to trust those values if they match the 1-hour precipitation.)"); + } - switch (dataSet) { - case "weather": - reportWeatherData(weather); - break; - case "forecast": - reportForecastData(weather); - break; - case "onecall": - reportOneCallData(weather); - break; - case "air_pollution": - reportAirPollutionData(weather); - break; - case "air_pollution/history": - case "air_pollution/forecast": - reportAirPollutionHistoryOrForecastData(weather, now); - break; - default: - System.out.println("No examples yet for this dataset."); - } + public static void main(String... args) { + Scanner scanner = new Scanner(System.in); + Instant now = Instant.now(); + String apiKey = null; + try { + apiKey = RestConnection.getApiKey("openweathermap"); + } catch (IOException ioException) { + System.err.println("IO Exception: " + ioException.getClass()); + System.err.println("\t" + ioException.getMessage()); + System.err.println("Caused by: " + ioException.getCause()); + System.err.println("\t" + ioException.getCause().getMessage()); + System.exit(1); + } - optionallySaveDataToFile(data, dataSet, scanner); - } - scanner.close(); - } + String dataSet = getDataSet(scanner); + OpenWeatherConnector weather = new OpenWeatherConnector(dataSet, apiKey); + String data = getData(weather, dataSet, now, scanner); + + System.out.println("Raw JSON: " + data); + if (data != null) { + System.out.println( + "Location: " + weather.getLatitude() + " latitude, " + weather.getLongitude() + " " + "longitude"); + Date currentTimeStamp = weather.getTimestamp(); + System.out.println("Current timestamp: " + + (currentTimeStamp == OpenWeatherConnector.IMPOSSIBLE_DATE ? "not present" : currentTimeStamp)); + System.out.println("Available timestamps: " + weather.getTimestamps()); + + switch (dataSet) { + case "weather": + reportWeatherData(weather); + break; + case "forecast": + reportForecastData(weather); + break; + case "onecall": + reportOneCallData(weather); + break; + case "air_pollution": + reportAirPollutionData(weather); + break; + case "air_pollution/history": + case "air_pollution/forecast": + reportAirPollutionHistoryOrForecastData(weather, now); + break; + default: + System.out.println("No examples yet for this dataset."); + } + + optionallySaveDataToFile(data, dataSet, scanner); + } + scanner.close(); + } } diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java index c1d8ce6..99ef769 100644 --- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java +++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/Connection.java @@ -9,14 +9,14 @@ import java.io.IOException; * Interface for connections to JSON data sources. */ public interface Connection { - /** - * Retrieves data in JSON format. - * - * @param dataSpecification identifies the data to be retrieved; the nature of this String depends on the - * implementing class - * @return requested data - * @throws IOException if the data cannot be requested or delivered - * @throws ParseException if the data is not a properly-formatted JSON string - */ - JSONObject get(String dataSpecification) throws IOException, ParseException; + /** + * Retrieves data in JSON format. + * + * @param dataSpecification identifies the data to be retrieved; the nature of + * this String depends on the implementing class + * @return requested data + * @throws IOException if the data cannot be requested or delivered + * @throws ParseException if the data is not a properly-formatted JSON string + */ + JSONObject get(String dataSpecification) throws IOException, ParseException; } diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java index 82c1cfd..5b83477 100644 --- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java +++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/FileConnection.java @@ -13,54 +13,55 @@ import java.util.Objects; * Connection to JSON files stored locally. */ public class FileConnection implements Connection { - protected String directory; + protected String directory; - /** - * Initiates connection to files at the top-level directory. - */ - public FileConnection() { - directory = ""; - } + /** + * Initiates connection to files at the top-level directory. + */ + public FileConnection() { + directory = ""; + } - /** - * Initiates connection to files in a particular directory. - * - * @param directory location of files that will be accessed - */ - public FileConnection(String directory) { - this.directory = directory + "/"; - } + /** + * Initiates connection to files in a particular directory. + * + * @param directory location of files that will be accessed + */ + public FileConnection(String directory) { + this.directory = directory + "/"; + } - /** - * Retrieves data from a JSON file. - * - * @param filename name of the file containing data - * @return requested data - * @throws IOException if the data cannot be requested or delivered; probably the most-common reason is that - * the requested file is not in the directory - * @throws ParseException if the data is not a properly-formatted JSON string - */ - public JSONObject get(String filename) throws IOException, ParseException { - JSONObject data; - try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull( - FileConnection.class.getClassLoader().getResourceAsStream(directory + filename)))) { - data = (JSONObject)new JSONParser().parse(inputStreamReader); - } catch (NullPointerException originalException) { - throw new IOException("Could not find " + directory + filename + ".", originalException); - } - return data; - } + /** + * Retrieves data from a JSON file. + * + * @param filename name of the file containing data + * @return requested data + * @throws IOException if the data cannot be requested or delivered; probably + * the most-common reason is that the requested file is + * not in the directory + * @throws ParseException if the data is not a properly-formatted JSON string + */ + public JSONObject get(String filename) throws IOException, ParseException { + JSONObject data; + try (InputStreamReader inputStreamReader = new InputStreamReader(Objects + .requireNonNull(FileConnection.class.getClassLoader().getResourceAsStream(directory + filename)))) { + data = (JSONObject) new JSONParser().parse(inputStreamReader); + } catch (NullPointerException originalException) { + throw new IOException("Could not find " + directory + filename + ".", originalException); + } + return data; + } - /** - * Saves data to a JSON file. - * - * @param filename name of the file that will hold the data - * @param data data to be saved - * @throws IOException if the data cannot be written to the file - */ - public void save(String filename, JSONObject data) throws IOException { - FileWriter fileWriter = new FileWriter(filename); - data.writeJSONString(fileWriter); - fileWriter.close(); - } + /** + * Saves data to a JSON file. + * + * @param filename name of the file that will hold the data + * @param data data to be saved + * @throws IOException if the data cannot be written to the file + */ + public void save(String filename, JSONObject data) throws IOException { + FileWriter fileWriter = new FileWriter(filename); + data.writeJSONString(fileWriter); + fileWriter.close(); + } } diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java b/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java index a7ada3f..293f3ea 100644 --- a/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java +++ b/src/main/java/edu/unl/cse/soft160/json_connections/connection/RestConnection.java @@ -19,79 +19,79 @@ import java.util.Objects; */ public class RestConnection implements Connection { - private static final String FILENAME = "apikeys.json"; + private static final String FILENAME = "apikeys.json"; - /** - * Retrieves the specified API key from the {@code apikeys.json} file. - * @param apiKeyName name of the key to be retrieved - * @return the API key - * @throws IOException if no data stored in {@code apikeys.json} could be retrieved - */ - public static String getApiKey(String apiKeyName) throws IOException { - JSONObject apiKeyJson; - try (InputStreamReader inputStreamReader = new InputStreamReader(Objects.requireNonNull( - Demonstration.class.getClassLoader().getResourceAsStream(FILENAME)))) { - apiKeyJson = (JSONObject)new JSONParser().parse(inputStreamReader); - } catch (NullPointerException nullPointerException) { - FileNotFoundException newException = new FileNotFoundException("File " + FILENAME + " not found."); - newException.initCause(nullPointerException); - throw newException; - } catch (ParseException parseException) { - throw new IOException("Error while parsing file " + FILENAME + ".", parseException); - } - if (!apiKeyJson.containsKey(apiKeyName)) { - System.err.println("WARNING! Could not locate API key named " + apiKeyName + " in file " + FILENAME + "."); - } - String apiKey = apiKeyJson.get(apiKeyName).toString(); - if (apiKey.equals("")) { - System.err.println("WARNING! API key named " + apiKeyName + " in file " + FILENAME + " is blank."); - } - return apiKey; - } + /** + * Retrieves the specified API key from the {@code apikeys.json} file. + * + * @param apiKeyName name of the key to be retrieved + * @return the API key + * @throws IOException if no data stored in {@code apikeys.json} could be + * retrieved + */ + public static String getApiKey(String apiKeyName) throws IOException { + JSONObject apiKeyJson; + try (InputStreamReader inputStreamReader = new InputStreamReader( + Objects.requireNonNull(Demonstration.class.getClassLoader().getResourceAsStream(FILENAME)))) { + apiKeyJson = (JSONObject) new JSONParser().parse(inputStreamReader); + } catch (NullPointerException nullPointerException) { + FileNotFoundException newException = new FileNotFoundException("File " + FILENAME + " not found."); + newException.initCause(nullPointerException); + throw newException; + } catch (ParseException parseException) { + throw new IOException("Error while parsing file " + FILENAME + ".", parseException); + } + if (!apiKeyJson.containsKey(apiKeyName)) { + System.err.println("WARNING! Could not locate API key named " + apiKeyName + " in file " + FILENAME + "."); + } + String apiKey = apiKeyJson.get(apiKeyName).toString(); + if (apiKey.equals("")) { + System.err.println("WARNING! API key named " + apiKeyName + " in file " + FILENAME + " is blank."); + } + return apiKey; + } - protected final String protocol; - protected final String authority; - protected final String path; - protected final String apiKey; + protected final String protocol; + protected final String authority; + protected final String path; + protected final String apiKey; - /** - * Initializes connection to REST API service. - * - * @param protocol transfer protocol to be used, typically as "http" - * @param authority service provider, typically the server's fully-resolved name - * @param path filepath on the authority to the REST service - * @param apiKey token provided by service owner to authenticate requester and grant appropriate privileges - */ - public RestConnection(String protocol, String authority, String path, String apiKey) { - this.protocol = protocol; - this.authority = authority; - this.path = path; - this.apiKey = apiKey; - } + /** + * Initializes connection to REST API service. + * + * @param protocol transfer protocol to be used, typically as "http" + * @param authority service provider, typically the server's fully-resolved name + * @param path filepath on the authority to the REST service + * @param apiKey token provided by service owner to authenticate requester + * and grant appropriate privileges + */ + public RestConnection(String protocol, String authority, String path, String apiKey) { + this.protocol = protocol; + this.authority = authority; + this.path = path; + this.apiKey = apiKey; + } - /** - * Retrieves data from REST service. - * - * @param query the REST query specifying the requested data - * @return requested data - * @throws IOException if the data cannot be requested or delivered, such as an incorrect URL or network problems - * @throws ParseException if the data is not a properly-formatted JSON string - */ - public JSONObject get(String query) throws IOException, ParseException { - JSONObject data; - try { - URLConnection connection = - new URI(protocol, - authority, - path, - query + "&appid=" + apiKey, - null).toURL().openConnection(); - connection.setRequestProperty("Accept", "application/json"); - InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream()); - data = (JSONObject)new JSONParser().parse(inputStreamReader); - } catch (URISyntaxException | MalformedURLException originalException) { - throw new IOException("Could not retrieve usable data from " + authority + ".", originalException); - } - return data; - } + /** + * Retrieves data from REST service. + * + * @param query the REST query specifying the requested data + * @return requested data + * @throws IOException if the data cannot be requested or delivered, such as + * an incorrect URL or network problems + * @throws ParseException if the data is not a properly-formatted JSON string + */ + public JSONObject get(String query) throws IOException, ParseException { + JSONObject data; + try { + URLConnection connection = new URI(protocol, authority, path, query + "&appid=" + apiKey, null).toURL() + .openConnection(); + connection.setRequestProperty("Accept", "application/json"); + InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream()); + data = (JSONObject) new JSONParser().parse(inputStreamReader); + } catch (URISyntaxException | MalformedURLException originalException) { + throw new IOException("Could not retrieve usable data from " + authority + ".", originalException); + } + return data; + } } diff --git a/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java b/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java index 3d64643..f0b3d47 100644 --- a/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java +++ b/src/main/java/edu/unl/cse/soft160/json_connections/connector/OpenWeatherConnector.java @@ -15,1498 +15,1938 @@ import java.util.List; import java.util.Set; /** - * <p>Wrapper for {@link Connection}s to OpenWeather data sources. Provides methods to extract values from OpenWeather - * data.</p> + * <p> + * Wrapper for {@link Connection}s to OpenWeather data sources. Provides methods + * to extract values from OpenWeather data. + * </p> * - * <p>All "get" methods will throw {@link IllegalStateException} if {@link #retrieveData(String)} had not been called. - * Most "get" methods will throw {@link UnsupportedOperationException} if called when the dataset is not relevant to the - * method (this distinguishes between a default value being returned because the requested datum isn't part of the data - * and an exceptional condition when the requested datum cannot be part of the data; see each method's JavaDoc for the - * relevant datasets).</p> + * <p> + * All "get" methods will throw {@link IllegalStateException} if + * {@link #retrieveData(String)} had not been called. Most "get" methods will + * throw {@link UnsupportedOperationException} if called when the dataset is not + * relevant to the method (this distinguishes between a default value being + * returned because the requested datum isn't part of the data and an + * exceptional condition when the requested datum cannot be part of the data; + * see each method's JavaDoc for the relevant datasets). + * </p> * - * @see <a href="https://openweathermap.org/api">OpenWeathermap.org API documentation</a> + * @see <a href="https://openweathermap.org/api">OpenWeathermap.org API + * documentation</a> */ public class OpenWeatherConnector { - /** - * <p>Top-level weather categories that may be reported in OpenWeather data.</p> - * - * <p>(n.b., {@link WeatherCategory#UNKNOWN_CATEGORY} is a catch-all for any reported categories that are not a - * documented weather condition.)</p> - * - * @see <a href="https://openweathermap.org/weather-conditions">OpenWeathermap Weather Conditions</a> - */ - public enum WeatherCategory { - UNKNOWN_CATEGORY, - THUNDERSTORM, // Group 2xx - DRIZZLE, // Group 3xx - RAIN, // Group 5xx - SNOW, // Group 6xx - // Group 7xx (Atmosphere) - MIST, // 701 - SMOKE, // 711 - HAZE, // 721 - DUST, // 731, 761 - FOG, // 741 - SAND, // 751 - ASH, // 762 - SQUALL, // 771 - TORNADO, // 781 - CLEAR, // Group 800 - CLOUDS, // Group 80x - } - - /** - * <p>Air Quality Indices reported in OpenWeather air pollution reports. Note that while openweathermap.org refers - * to the Air Quality Indices on a scale of Good (1) to Very Poor (5), the CAQI Air Quality Index report refers to - * the Air Quality Indices as a level of pollutants on a scale of Very Low (1) to Very High (5). Numerically they - * are equivalent but the English-language meaning is different. This enumerated type uses the CAQI - * nomenclature.</p> - * - * <p>(n.b., {@link AirQuality#UNKNOWN_AIR_QUALITY} is a catch-all when no air quality data is present.)</p> - * - * @see <a href="https://openweathermap.org/api/air-pollution">OpenWeathermap Air Pollution API</a> - * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a> - * @see - * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a> - */ - public enum AirQuality { - UNKNOWN_AIR_QUALITY, - VERY_LOW, // aqi==1 "Good" in openweathermap.org/api/air-pollution - LOW, // aqi==2 "Fair" in openweathermap.org/api/air-pollution - MEDIUM, // aqi==3 "Moderate" in openweathermap.org/api/air-pollution - HIGH, // aqi==4 "Poor" in openweathermap.org/api/air-pollution - VERY_HIGH, // aqi==5 "Very Poor" in openweathermap.org/api/air-pollution - } - - /** - * Supported data sets, a subset of the documented OpenWeathermap APIs. - */ - public static final Set<String> allowableDataSets = Set.of( - "weather", - "onecall", "onecall/timemachine", - "forecast", - "air_pollution", "air_pollution/forecast", "air_pollution/history", - "direct", "reverse" // geocoding - // "stations", "triggers" excluded because PUT/POST calls are not supported here - // "map" excluded because it isn't JSON and also appears not to be a REST call - ); - - public static final Date IMPOSSIBLE_DATE = new Date(Long.MIN_VALUE); - public static final String PROTOCOL = "http"; - public static final String REST_AUTHORITY = "api.openweathermap.org"; - - protected final Connection dataSource; - protected String dataSet; - protected String REST_PATH; // Should be able to declare this as final, but static analysis doesn't see that - - protected JSONObject data; - protected Date currentTimestamp; - - /** - * <p>Constructor to be used when connecting to OpenWeather data stored in a local file.</p> - * - * <p><i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, the data set is of the form - * "air_pollution/forecast" and "air_pollution/history".</p> - * - * @param fileDataSet directory containing the specified file; must correspond to one of the - * <a href="https://openweathermap.org/api">OpenWeathermap.org APIs</a> - * @throws IllegalArgumentException if {@code fileDataSet} does not correspond to an OpenWeathermap.org API - */ - public OpenWeatherConnector(String fileDataSet) throws IllegalArgumentException { - initializeFields(fileDataSet); - dataSource = new FileConnection(fileDataSet); - } - - /** - * <p>Constructor to be used when connecting to <a href="https://openweathermap.org">OpenWeathermap.org</a>s's - * REST API.</p> - * - * <p><i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, the data set is of the form - * "air_pollution/forecast" and "air_pollution/history".</p> - * - * @param restDataSet specific <a href="https://openweathermap.org/api">OpenWeathermap.org API</a> to be used - * @param apiKey token provided by <a href="https://openweathermap.org">OpenWeathermap.org</a> - * to authenticate requester and grant appropriate privileges - * @throws IllegalArgumentException if {@code fileDataSet} does not correspond to an OpenWeathermap.org API - */ - public OpenWeatherConnector(String restDataSet, String apiKey) throws IllegalArgumentException { - initializeFields(restDataSet); - dataSource = new RestConnection(PROTOCOL, REST_AUTHORITY, REST_PATH + restDataSet, apiKey); - } - - private void initializeFields(String intendedDataSet) throws IllegalArgumentException { - if (!allowableDataSets.contains(intendedDataSet)) { - throw new IllegalArgumentException(intendedDataSet + " is not a valid data set."); - } - dataSet = intendedDataSet; - switch (dataSet) { - case "weather": - case "onecall": - case "onecall/timemachine": - case "forecast": - case "air_pollution": - case "air_pollution/forecast": - case "air_pollution/history": - REST_PATH = "/data/2.5/"; - break; - case "direct": - case "reverse": - REST_PATH = "/geo/1.0/"; - break; - default: - REST_PATH = "unknown"; - } - data = null; - currentTimestamp = null; - } - - /** - * Retrieves requested data from the data set. Must be called at least once (without data, the other methods have - * no data to work with). The data will be stored as part of the {@link OpenWeatherConnector} instance; however, - * the JSON string will also be returned. - * - * @param requestedData the data to be retrieved. If connected to the local file system, this is the name of the - * file with the data. If connected to - * <a href="https://openweathermap.org">OpenWeathermap.org/api</a> - * 's REST API, this is the query string. - * @return JSON string for the requested data - * @throws IOException if the data cannot be retrieved - */ - public String retrieveData(String requestedData) throws IOException { - try { - data = dataSource.get(requestedData); - } catch (FileNotFoundException fileNotFoundException) { - if (dataSource instanceof RestConnection) { - throw new IOException("Could not access \"" + dataSet + "\" dataset at " + REST_AUTHORITY + ".", - fileNotFoundException); - } else { - throw fileNotFoundException; // For FileConnection, this exception is exactly what's on the label, - } // except that we'd more likely see a NullPointerException... - } catch (NullPointerException nullPointerException) { - if (dataSource instanceof FileConnection) { - FileNotFoundException newException = new FileNotFoundException("File " + requestedData + " not found."); - newException.initCause(nullPointerException); - throw newException; - } else { - throw nullPointerException; // Not going to try to predict why RestConnection generates NPE - } - } catch (ParseException parseException) { - String message; - if (dataSource instanceof FileConnection) { - message = "Error while parsing file " + requestedData + "."; - } else if (dataSource instanceof RestConnection) { - message = "Error while parsing the " + dataSet + " response from " + REST_AUTHORITY + "."; - } else { - message = "Error while parsing requested data."; - } - throw new IOException(message, parseException); - } - checkForDataReadiness(null); - long unixTime = extractLongFromJSON(data, "dt", extractLongFromJSON(data, "current", "dt", - Long.MIN_VALUE)); - if (unixTime == Long.MIN_VALUE && data.containsKey("list") && ((JSONArray)data.get("list")).size() == 1) { - // this is how current air quality data is reported - unixTime = (Long)((JSONObject)((JSONArray)data.get("list")).get(0)).get("dt"); - } - currentTimestamp = unixTime == Long.MIN_VALUE ? IMPOSSIBLE_DATE : new Date(unixTime * 1000); - return data.toJSONString(); - } - - /* - * Helper Methods - */ - - /** - * Checks whether {@link #data} was populated by calling {@link #retrieveData(String)} and whether the calling - * method can use the dataset specified in the constructor call. - * - * @param supportedDataSets the datasets that are relevant to the calling method or {@code null} if all datasets are - * relevant - * @throws IllegalStateException if no data has been retrieved using {@link #retrieveData(String)} - * @throws UnsupportedOperationException if the dataset specified in the constructor call does not apply to the - * method that called {@code checkForDataPresence(Set)} - */ - private void checkForDataReadiness(Set<String> supportedDataSets) - throws IllegalStateException, UnsupportedOperationException { - if (data == null) { - throw new IllegalStateException("No data has been retrieved from the " + dataSet + " dataset."); - } - if (supportedDataSets != null && !supportedDataSets.contains(dataSet)) { - throw new UnsupportedOperationException("Attempted to call method on an inapplicable dataset (" + dataSet + - "). Applicable dataset(s): " + supportedDataSets + "."); - } - } - - /** - * Returns value associated with the key in the JSON object. The caller is responsible for making sure that the - * JSON object is not null; however, the caller does <i>not</i> need to establish that the key is present. - * Returns the default value if the key is not present. - * - * @param jsonObject JSON object that may contain the key and value of interest - * @param key the key of interest - * @param defaultValue the value to be returned if the key is not present - * @return the value of interest, or the default value if the key is not present - */ - private double extractDoubleFromJSON(JSONObject jsonObject, String key, double defaultValue) { - double returnValue = defaultValue; - if (jsonObject.containsKey(key)) { - Number value = (Number)jsonObject.get(key); - returnValue = value == null ? defaultValue : value.doubleValue(); - } - return returnValue; - } - - /** - * Returns value associated with the key in a second-level JSON object in the specified JSON object. The caller - * is responsible for making sure that the JSON object is not null; however, the caller does <i>not</i> need to - * establish that the key is present. Returns the default value if the key is not present. - * - * @param jsonObject JSON object that may contain the key and value of interest - * @param topLevelField the key to access the second-level JSON object - * @param subField the key of interest in the second-level JSON object - * @param defaultValue the value to be returned if the key is not present - * @return the value of interest, or the default value if the key is not present - */ - private double extractDoubleFromJSON(JSONObject jsonObject, String topLevelField, String subField, - double defaultValue) { - double returnValue = defaultValue; - if (jsonObject.containsKey(topLevelField)) { - JSONObject secondLevelJsonObject = (JSONObject)jsonObject.get(topLevelField); - returnValue = extractDoubleFromJSON(secondLevelJsonObject, subField, defaultValue); - } - return returnValue; - } - - /** - * Returns value associated with the key in the JSON object. The caller is responsible for making sure that the - * JSON object is not null; however, the caller does <i>not</i> need to establish that the key is present. - * Returns the default value if the key is not present. - * - * @param jsonObject JSON object that may contain the key and value of interest - * @param key the key of interest - * @param defaultValue the value to be returned if the key is not present - * @return the value of interest, or the default value if the key is not present - */ - private long extractLongFromJSON(JSONObject jsonObject, String key, long defaultValue) { - long returnValue = defaultValue; - if (jsonObject.containsKey(key)) { - Long value = (Long)jsonObject.get(key); - returnValue = value == null ? defaultValue : value; - } - return returnValue; - } - - /** - * Returns value associated with the key in a second-level JSON object in the specified JSON object. The caller - * is responsible for making sure that the JSON object is not null; however, the caller does <i>not</i> need to - * establish that the key is present. Returns the default value if the key is not present. - * - * @param jsonObject JSON object that may contain the key and value of interest - * @param topLevelField the key to access the second-level JSON object - * @param subField the key of interest in the second-level JSON object - * @param defaultValue the value to be returned if the key is not present - * @return the value of interest, or the default value if the key is not present - */ - private long extractLongFromJSON(JSONObject jsonObject, String topLevelField, String subField, long defaultValue) { - long returnValue = defaultValue; - if (jsonObject.containsKey(topLevelField)) { - JSONObject secondLevelJsonObject = (JSONObject)jsonObject.get(topLevelField); - returnValue = extractLongFromJSON(secondLevelJsonObject, subField, defaultValue); - } - return returnValue; - } - - /** - * Returns object in the list associated with the key, at the specified timestamp. Returns null if the list is not - * present, or if there is no list entry at the timestamp. - * - * @param listName the key to access the list - * @param timestamp the timestamp of the list entry - * @return the object of interest, or null if the list or the timestamp are not present - */ - private JSONObject getListEntry(String listName, Date timestamp) { - JSONObject listEntry = null; - if (data.containsKey(listName)) { - JSONArray list = (JSONArray)data.get(listName); - for (Object entry : list) { - if ((Long)((JSONObject)entry).get("dt") == timestamp.getTime() / 1000) { - listEntry = (JSONObject)entry; - } - } - } - return listEntry; - } - - /* - * Wrapper methods for all reports - */ - - /** - * <p>Provides the latitude for the weather's location.</p> - * <p>Available for all datasets.</p> - * - * @return location's latitude - */ - public double getLatitude() { - checkForDataReadiness(null); - JSONObject locationContainer = data; - if (data.containsKey("city")) { - locationContainer = (JSONObject)data.get("city"); - } - if (dataSet.startsWith("onecall")) { - return extractDoubleFromJSON(locationContainer, "lat", Double.NaN); - } else { - return extractDoubleFromJSON(locationContainer, "coord", "lat", Double.NaN); - } - } - - /** - * <p>Provides the longitude for the weather's location.</p> - * <p>Available for all datasets.</p> - * - * @return location's longitude - */ - public double getLongitude() { - checkForDataReadiness(null); - JSONObject locationContainer = data; - if (data.containsKey("city")) { - locationContainer = (JSONObject)data.get("city"); - } - if (dataSet.startsWith("onecall")) { - return extractDoubleFromJSON(locationContainer, "lon", Double.NaN); - } else { - return extractDoubleFromJSON(locationContainer, "coord", "lon", Double.NaN); - } - } - - /** - * <p>Provides the date and time for the current weather, or {@link #IMPOSSIBLE_DATE} if no valid timestamp - * exists.</p> - * <p>Available for all datasets with data for the present.</p> - * - * @return timestamp for the weather observations - */ - public Date getTimestamp() { - checkForDataReadiness(null); - return currentTimestamp; - } - - /** - * Extracts epoch-based timestamps from the specified JSON list and places {@link Date} timestamps into the provided - * {@link List}. - * @param jsonListName the name of the JSON list containing data with timestamps - * @param timestamps the possibly-nonempty {@link List} to place the {@link Date} timestamps in - */ - private void moveTimestampsFromJsonArrayToJavaList(String jsonListName, List<Date> timestamps) { - if (data.containsKey(jsonListName)) { - JSONArray entries = (JSONArray)data.get(jsonListName); - if (entries != null) { - for (Object entry : entries) { - long unixTime = (Long)((JSONObject)entry).get("dt"); - timestamps.add(new Date(unixTime * 1000)); - } - } - } - } - - /** - * <p>Provides all dates and times for reports with multiple timestamps.</p> - * <p>Available for all datasets with data in the past or the future.</p> - * - * @return list of timestamps for the weather observations - */ - public List<Date> getTimestamps() { - checkForDataReadiness(null); - Set<String> possibleListNames = Set.of("list", "minutely", "hourly", "daily"); - List<Date> timestamps = new ArrayList<>(); - for (String listName : possibleListNames) { - moveTimestampsFromJsonArrayToJavaList(listName, timestamps); - } - timestamps.sort(null); - return List.copyOf(timestamps); - } - - /** - * <p>Provides the dates and times for a specific list, for reports with multiple timestamps.</p> - * <p>Available for all datasets with data in the past or the future.</p> - * - * @param listName the name of the list whose timestamps are of interest - * @return list of timestamps for the weather observations - */ - public List<Date> getTimestamps(String listName) { - checkForDataReadiness(null); - List<Date> timestamps = new ArrayList<>(); - moveTimestampsFromJsonArrayToJavaList(listName, timestamps); - timestamps.sort(null); - return List.copyOf(timestamps); - } - - /* - * Wrapper methods for current and forecasted weather - */ - - /** - * <p>Provides the broad categories for the weather reported in the provided JSON object. If there are more than - * one category provided, the "primary" category will at the head of the list. The weather categories are guaranteed - * to be in the same order as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p> - * <p>The caller is responsible for ensuring that data is present.</p> - * - * @param jsonObject the object containing the weather data - * @return list of weather categories - * @see #getWeatherDescriptions() - */ - private List<WeatherCategory> getWeatherCategories(JSONObject jsonObject) { - JSONArray weather = (JSONArray)jsonObject.get("weather"); - List<WeatherCategory> categories; - if (weather != null) { - categories = new ArrayList<>(weather.size()); - for (Object condition : weather) { - String category = ((JSONObject)condition).get("main").toString(); - try { - categories.add(WeatherCategory.valueOf(category.toUpperCase())); - } catch (IllegalArgumentException ignored) { - categories.add(WeatherCategory.UNKNOWN_CATEGORY); - } - } - } else { - categories = new ArrayList<>(0); - } - return List.copyOf(categories); - } - - /** - * <p>Provides the broad categories for the current weather. If there are more than one category provided, the - * "primary" category will at the head of the list. The weather categories are guaranteed to be in - * the same order as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return list of weather categories - * @see #getWeatherDescriptions() - */ - public List<WeatherCategory> getWeatherCategories() { - checkForDataReadiness(Set.of("weather", "onecall")); - return getWeatherCategories(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data); - } - - /** - * <p>Provides the broad categories for the forecasted weather. If there are more than one category provided, the - * "primary" category will at the head of the list. The weather categories are guaranteed to be in the same order - * as the corresponding descriptions provided by {@link #getWeatherDescriptions()}.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return list of forecasted weather categories - * @see #getWeatherDescriptions() - */ - public List<WeatherCategory> getWeatherCategories(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - String listName = "list"; - if (dataSet.equals("onecall")) { - List<Date> hours = getTimestamps("hourly"); - listName = hours.contains(timestamp) ? "hourly" : "daily"; - } - return getWeatherCategories(getListEntry(listName, timestamp)); - } - - /** - * <p>Provides descriptions of the weather reported in the provided JSON object. If there are more than one weather - * description provided, the "primary" description will be at the head of the list. The weather descriptions are - * guaranteed to be in the same order as the corresponding categories provided by - * {@link #getWeatherCategories()}.</p> - * <p>The caller is responsible for ensuring that data is present.</p> - * - * @param jsonObject the object containing the weather data - * @return list of weather descriptions - * @see #getWeatherCategories() - */ - private List<String> getWeatherDescriptions(JSONObject jsonObject) { - JSONArray weather = (JSONArray)jsonObject.get("weather"); - List<String> descriptions; - if (weather != null) { - descriptions = new ArrayList<>(weather.size()); - for (Object condition : weather) { - descriptions.add(((JSONObject)condition).get("description").toString()); - } - } else { - descriptions = new ArrayList<>(0); - } - return List.copyOf(descriptions); - } - - /** - * <p>Provides descriptions of the current weather. If there are more than one weather description provided, the - * "primary" description will be at the head of the list. The weather descriptions are guaranteed to be in the - * same order as the corresponding categories provided by {@link #getWeatherCategories()}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return list of weather descriptions - * @see #getWeatherCategories() - */ - public List<String> getWeatherDescriptions() { - checkForDataReadiness(Set.of("weather", "onecall")); - return getWeatherDescriptions(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data); - } - - /** - * <p>Provides descriptions of the forecasted weather. If there are more than one weather description provided, - * the "primary" description will be at the head of the list. The weather descriptions are guaranteed to be in - * the same order as the corresponding categories provided by {@link #getWeatherCategories()}.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return list of forecasted weather descriptions - * @see #getWeatherCategories() - */ - public List<String> getWeatherDescriptions(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - String listName = "list"; - if (dataSet.equals("onecall")) { - List<Date> hours = getTimestamps("hourly"); - listName = hours.contains(timestamp) ? "hourly" : "daily"; - } - return getWeatherDescriptions(getListEntry(listName, timestamp)); - } - - /** - * <p>Provides the current visibility in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current visibility, or {@link Long#MIN_VALUE} if visibility is not in current observation - */ - public long getVisibility() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractLongFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data, - "visibility", Long.MIN_VALUE); - } - - /** - * <p>Provides the forecasted visibility in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted visibility, or {@link Long#MIN_VALUE} if visibility is not in the forecast - */ - public long getVisibility(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("onecall") && !getTimestamps("hourly").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); - } - String listName = dataSet.equals("onecall") ? "hourly" : "list"; - return extractLongFromJSON(getListEntry(listName, timestamp), "visibility", Long.MIN_VALUE); - } - - /** - * <p>Provides the current temperature in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current temperature, or {@link Double#NaN} if temperature is not in current observation - */ - public double getTemperature() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractDoubleFromJSON(data, - dataSet.startsWith("onecall") ? "current" : "main", "temp", Double.NaN); - } - - /** - * <p>Provides the forecasted temperature in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted temperature, or {@link Double#NaN} if temperature is not in the forecast - */ - public double getTemperature(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "temp", Double.NaN); - } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) { - return extractDoubleFromJSON(getListEntry("hourly", timestamp), "temp", Double.NaN); - } else { - throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); - } - } - - /** - * <p>Provides the forecasted morning temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted morning temperature, or {@link Double#NaN} if morning temperature is not in the forecast - */ - public double getMorningTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "morn", Double.NaN); - } - - /** - * <p>Provides the forecasted daytime temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted daytime temperature, or {@link Double#NaN} if daytime temperature is not in the forecast - */ - public double getDaytimeTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "day", Double.NaN); - } - - /** - * <p>Provides the forecasted evening temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted evening temperature, or {@link Double#NaN} if evening temperature is not in the forecast - */ - public double getEveningTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "eve", Double.NaN); - } - - /** - * <p>Provides the forecasted nighttime temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted nighttime temperature, or {@link Double#NaN} if nighttime temperature is not in the - * forecast - */ - public double getNighttimeTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "night", Double.NaN); - } - - /** - * <p>Provides the forecasted daily low temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted daily low temperature, or {@link Double#NaN} if daily low temperature is not in the - * forecast - */ - public double getLowTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "min", Double.NaN); - } - - /** - * <p>Provides the forecasted daily high temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted daily high temperature, or {@link Double#NaN} if daily high temperature is not in the - * forecast - */ - public double getHighTemperature(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "max", Double.NaN); - } - - /** - * <p>Provides the current relative humidity (percent of saturation).</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current humidity, or {@link Long#MIN_VALUE} if visibility is not in current observation - */ - public long getHumidity() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractLongFromJSON(data, - dataSet.startsWith("onecall") ? "current" : "main", "humidity", Long.MIN_VALUE); - } - - /** - * <p>Provides the forecasted relative humidity (percent of saturation).</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted humidity, or {@link Long#MIN_VALUE} if visibility is not in the forecast - */ - public long getHumidity(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractLongFromJSON(getListEntry("list", timestamp), "main", "humidity", Long.MIN_VALUE); - } else if (dataSet.equals("onecall")) { - return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "humidity", Long.MIN_VALUE); - } else { - return Long.MIN_VALUE; - } - } - - /** - * <p>Provides the current dew point in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @return the current dew point, or {@link Double#NaN} if dew point is not in current observation - */ - public double getDewPoint() { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(data, "current", "dew_point", Double.NaN); - } - - /** - * <p>Provides the forecasted dew point in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted dew point, or {@link Double#NaN} if dew point is not in the forecast - */ - public double getDewPoint(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "dew_point", Double.NaN); - } - - /** - * <p>Provides the current "feels like" temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current "feels like" temperature, or {@link Double#NaN} if "feels like" temperature is not in - * current observation - */ - public double getFeelsLike() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractDoubleFromJSON(data, - dataSet.startsWith("onecall") ? "current" : "main", "feels_like", Double.NaN); - } - - /** - * <p>Provides the forecasted "feels like" temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" (hourly only) datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted "feels like" temperature, or {@link Double#NaN} if "feels like" temperature is not in - * the forecast - */ - public double getFeelsLike(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "feels_like", Double.NaN); - } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) { - return extractDoubleFromJSON(getListEntry("hourly", timestamp), "feels_like", Double.NaN); - } else { - throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); - } - } - - /** - * <p>Provides the forecasted morning "feels like" temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted morning "feels like" temperature, or {@link Double#NaN} if morning "feels like" - * temperature is not in the forecast - */ - public double getMorningFeelsLike(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "morn", Double.NaN); - } - - /** - * <p>Provides the forecasted "feels like" daytime temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted daytime "feels like" temperature, or {@link Double#NaN} if daytime "feels like" - * temperature is not in the forecast - */ - public double getDaytimeFeelsLike(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "day", Double.NaN); - } - - /** - * <p>Provides the forecasted evening "feels like" temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted evening "feels like" temperature, or {@link Double#NaN} if evening "feels like" - * temperature is not in the forecast - */ - public double getEveningFeelsLike(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "eve", Double.NaN); - } - - /** - * <p>Provides the forecasted nighttime "feels like" temperature in the default - * <a href="https://openweathermap.org/current#data">units</a> or those specified in the call to - * {@link #retrieveData(String)}.</p> - * <p>Available for the "onecall" (daily only) dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted nighttime "feels like" temperature, or {@link Double#NaN} if nighttime "feels like" - * temperature is not in the - * forecast - */ - public double getNighttimeFeelsLike(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("daily").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); - } - return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "night", Double.NaN); - } - - /** - * <p>Provides the current pressure in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current pressure, or {@link Long#MIN_VALUE} if pressure is not in current observation - */ - public long getPressure() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractLongFromJSON(data, - dataSet.startsWith("onecall") ? "current" : "main", "pressure", Long.MIN_VALUE); - } - - /** - * <p>Provides the forecasted pressure in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted pressure, or {@link Long#MIN_VALUE} if pressure is not in the forecast - */ - public long getPressure(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractLongFromJSON(getListEntry("list", timestamp), "main", "pressure", Long.MIN_VALUE); - } else if (dataSet.equals("onecall")) { - return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "pressure", Long.MIN_VALUE); - } else { - return Long.MIN_VALUE; - } - } - - /** - * <p>Provides the current wind direction, in degrees.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current wind direction, or {@link Long#MIN_VALUE} if winds are not in current observation - */ - public long getWindDirection() { - checkForDataReadiness(Set.of("weather", "onecall")); - if (dataSet.startsWith("onecall")) { - return extractLongFromJSON(data, "current", "wind_deg", Long.MIN_VALUE); - } else { - return extractLongFromJSON(data, "wind", "deg", Long.MIN_VALUE); - } - } - - /** - * <p>Provides the forecasted wind direction, in degrees.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted wind direction, or {@link Long#MIN_VALUE} if winds are not in the forecast - */ - public long getWindDirection(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractLongFromJSON(getListEntry("list", timestamp), "wind", "deg", Long.MIN_VALUE); - } else if (dataSet.equals("onecall")) { - return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "wind_deg", Long.MIN_VALUE); - } else { - return Long.MIN_VALUE; - } - } - - /** - * <p>Provides the current wind speed in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current wind speed, or 0.0 if winds are not in current observation - */ - public double getWindSpeed() { - checkForDataReadiness(Set.of("weather", "onecall")); - if (dataSet.startsWith("onecall")) { - return extractDoubleFromJSON(data, "current", "wind_speed", 0.0); - } else { - return extractDoubleFromJSON(data, "wind", "speed", 0.0); - } - } - - /** - * <p>Provides the forecasted wind speed in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted wind speed, or 0.0 if winds are not in the forecast - */ - public double getWindSpeed(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "speed", 0.0); - } else if (dataSet.equals("onecall")) { - return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "wind_speed", 0.0); - } else { - return 0.0; - } - } - - /** - * <p>Provides the current wind gust in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current wind gust, or current wind speed if wind gust is not in current observation - */ - public double getWindGust() { - checkForDataReadiness(Set.of("weather", "onecall")); - if (dataSet.startsWith("onecall")) { - return extractDoubleFromJSON(data, "current", "wind_gust", getWindSpeed()); - } else { - return extractDoubleFromJSON(data, "wind", "gust", getWindSpeed()); - } - } - - /** - * <p>Provides the forecasted wind gust in the default <a href="https://openweathermap.org/current#data">units</a> - * or those specified in the call to {@link #retrieveData(String)}.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted wind gust, or current wind speed if wind gust is not in the forecast - */ - public double getWindGust(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.equals("forecast")) { - return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "gust", getWindSpeed(timestamp)); - } else if (dataSet.equals("onecall")) { - return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "wind_gust", getWindSpeed(timestamp)); - } else { - return getWindSpeed(timestamp); - } - } - - /** - * <p>Provides the current UV Index.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @return the current UV Index, or {@link Double#NaN} if the UV Index is not in current observation - */ - public double getUltravioletIndex() { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(data, "current", "uvi", Double.NaN); - } - - /** - * <p>Provides the forecasted UV Index.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted UV Index, or {@link Double#NaN} if the UV Index is not in the forecast - */ - public double getUltravioletIndex(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "uvi", Double.NaN); - } - - /** - * <p>Provides the current cloud cover percentage (cloudiness).</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current cloudiness, or 0 if cloudiness is not in current observation - */ - public long getCloudCover() { - checkForDataReadiness(Set.of("weather", "onecall")); - if (dataSet.startsWith("onecall")) { - return extractLongFromJSON(data, "clouds", 0); - } else { - return extractLongFromJSON(data, "clouds", "all", 0); - } - } - - /** - * <p>Provides the forecasted cloud cover percentage (cloudiness).</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted cloudiness, or 0 if cloudiness is not in current observation - */ - public long getCloudCover(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - if (dataSet.startsWith("onecall")) { - return extractLongFromJSON(getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", - timestamp), "clouds", 0); - } else { - return extractLongFromJSON(getListEntry("list", timestamp), "clouds", "all", 0); - } - } - - /** - * <p>Provides the forecasted probability of rain, on a 0.0-1.0 scale.</p> - * <p>Available for the "forecast" and "onecall" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return the forecasted probability of precipitation, or NaN if cloudiness is not in current observation - */ - public double getProbabilityOfPrecipitation(Date timestamp) { - checkForDataReadiness(Set.of("forecast", "onecall")); - String listName = "list"; - if (dataSet.equals("onecall")) { - List<Date> hours = getTimestamps("hourly"); - listName = hours.contains(timestamp) ? "hourly" : "daily"; - } - return extractDoubleFromJSON(getListEntry(listName, timestamp), "pop", Double.NaN); - } - - /** - * <p>Provides the one-hour rainfall total column, in millimeters.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current one-hour rainfall total, or 0.0 if rain volume is not in current observation - */ - public double getOneHourRainfall() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data, - "rain", "1h", 0.0); - } - - /** - * <p>Provides the total rain column, in millimeters, forecasted for the one hour before the specified - * timestamp.</p> - * <p>Available for the "onecall" (hourly only) dataset.</p> - * - * @param timestamp the timestamp for the forecasted rainfall - * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not in the forecast - */ - public double getOneHourRainfall(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("hourly").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); - } - return extractDoubleFromJSON(getListEntry("hourly", timestamp), "rain", "1h", 0.0); - } - - /** - * <p>Provides the three-hour rainfall total column, in millimeters.</p> - * <p>Available for the "weather" dataset.</p> - * - * @return the current three-hour rainfall total, or 0.0 if rain volume is not in current observation - */ - public double getThreeHourRainfall() { - checkForDataReadiness(Set.of("weather")); - return extractDoubleFromJSON(data, "rain", "3h", getOneHourRainfall()); - } - - /** - * <p>Provides the total rain column, in millimeters, forecasted for the three hours before the specified - * timestamp.</p> - * <p>Available for the "forecast" dataset.</p> - * - * @param timestamp the timestamp for the forecasted rainfall - * @return the forecasted three-hour rainfall total, or 0.0 if rain volume is not in the forecast - */ - public double getThreeHourRainfall(Date timestamp) { - checkForDataReadiness(Set.of("forecast")); - return extractDoubleFromJSON(getListEntry("list", timestamp), "rain", "3h", 0.0); - } - - /** - * <p>Provides the one-hour snowfall total column, in millimeters.</p> - * <p>Available for the "weather" and "onecall" datasets.</p> - * - * @return the current one-hour snowfall total, or 0.0 if snow volume is not in current observation - */ - public double getOneHourSnowfall() { - checkForDataReadiness(Set.of("weather", "onecall")); - return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject)data.get("current") : data, - "snow", "1h", 0.0); - } - - /** - * <p>Provides the total snow column, in millimeters, forecasted for the one hour before the specified - * timestamp.</p> - * <p>Available for the "onecall" (hourly only) dataset.</p> - * - * @param timestamp the timestamp for the forecasted snowfall - * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not in the forecast - */ - public double getOneHourSnowfall(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("hourly").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); - } - return extractDoubleFromJSON(getListEntry("hourly", timestamp), "snow", "1h", 0.0); - } - - /** - * <p>Provides the three-hour snowfall total column, in millimeters.</p> - * <p>Available for the "weather" dataset.</p> - * - * @return the current three-hour snowfall total, or 0.0 if snow volume is not in current observation - */ - public double getThreeHourSnowfall() { - checkForDataReadiness(Set.of("weather")); - return extractDoubleFromJSON(data, "snow", "3h", getOneHourSnowfall()); - } - - /** - * <p>Provides the total snow column, in millimeters, forecasted for the three hours before the specified - * timestamp.</p> - * <p>Available for the "forecast" dataset.</p> - * - * @param timestamp the timestamp for the forecasted snowfall - * @return the forecasted three-hour snowfall total, or 0.0 if snow volume is not in the forecast - */ - public double getThreeHourSnowfall(Date timestamp) { - checkForDataReadiness(Set.of("forecast")); - return extractDoubleFromJSON(getListEntry("list", timestamp), "snow", "3h", 0.0); - } - - /** - * <p>Provides the precipitation column, in millimeters, forecasted for the the specified minute. Not explicitly - * stated in the API specification, this appears to be a 1-hour total that does not distinguish between rain and - * snow.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @param timestamp the timestamp for the forecasted precipitation - * @return the forecasted precipitation total, or 0.0 if precipitation volume is not in the forecast - */ - public double getMinutelyPrecipitation(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - if (!getTimestamps("minutely").contains(timestamp)) { - throw new UnsupportedOperationException("This onecall datum is only available for minutely timestamps."); - } - return extractDoubleFromJSON(getListEntry("minutely", timestamp), "precipitation", 0.0); - } - - /** - * <p>Provides the rain column, in millimeters, forecasted for the the specified day. Not explicitly stated in the - * API specification, this appears to be a daily total.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @param timestamp the timestamp for the forecasted rainfall - * @return the forecasted rain total, or 0.0 if precipitation volume is not in the forecast - */ - public double getDailyRainfall(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(getListEntry("daily", timestamp), "rain", 0.0); - } - - /** - * <p>Provides the snow column, in millimeters, forecasted for the the specified day. Not explicitly stated in the - * API specification, this appears to be a daily total.</p> - * <p>Available for the "onecall" dataset.</p> - * - * @param timestamp the timestamp for the forecasted snowfall - * @return the forecasted snow total, or 0.0 if precipitation volume is not in the forecast - */ - public double getDailySnowfall(Date timestamp) { - checkForDataReadiness(Set.of("onecall")); - return extractDoubleFromJSON(getListEntry("daily", timestamp), "snow", 0.0); - } - - /* - * Wrapper methods for Air Quality - */ - - /** - * Returns the concentration for the specified pollutant at the specified timestamp from the list of air quality - * entries. - * - * @param timestamp the timestamp for the air quality entry - * @param pollutant the pollutant whose concentration is to be obtained - * @return the value associated with the specified pollutant at the specified timestamp - */ - private double getPollutionData(Date timestamp, String pollutant) { - JSONObject currentEntry = getListEntry("list", timestamp); - if (currentEntry == null) { - return Double.NaN; - } else { - return extractDoubleFromJSON(currentEntry, "components", pollutant, Double.NaN); - } - } - - /** - * <p>Provides the current basic Air Quality Index, using the European CAQI tables. This is a composite metric - * based on concentrations of nitrogen monoxide, ozone, coarse particulates, and optionally fine particulates.</p> - * - * <p>The air quality is reported on a range from {@link AirQuality#VERY_LOW} (good) to - * {@link AirQuality#VERY_HIGH} (very poor)</p> - * - * <p>Available for the "air_pollution" dataset.</p> - * - * @return air quality index at the requested timestamp - * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a> - * @see - * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a> - */ - public AirQuality getAirQualityIndex() { - checkForDataReadiness(Set.of("air_pollution")); - return getAirQualityIndex(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted basic Air Quality Index, using the European CAQI tables. This - * is a composite metric based on concentrations of nitrogen monoxide, ozone, coarse particulates, and optionally - * fine particulates.</p> - * - * <p>The air quality is reported on a range from {@link AirQuality#VERY_LOW} (good) to - * {@link AirQuality#VERY_HIGH} (very poor)</p> - * - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return air quality index at the requested timestamp - * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality Index entry on Wikipedia</a> - * @see - * <a href="https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI Air Quality Index</a> - */ - public AirQuality getAirQualityIndex(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - JSONObject currentEntry = getListEntry("list", timestamp); - int airQualityIndex = 0; - if (currentEntry != null) { - airQualityIndex = (int)extractLongFromJSON(currentEntry, "main", "aqi", 0); - } - return AirQuality.values()[airQualityIndex]; - } - - /** - * <p>Provides the current concentration of Carbon Monoxide (CO), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of CO - */ - public double getCarbonMonoxide() { - checkForDataReadiness(Set.of("air_pollution")); - return getCarbonMonoxide(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Carbon Monoxide (CO), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of CO at the requested timestamp - */ - public double getCarbonMonoxide(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "co"); - } - - /** - * <p>Provides the current concentration of Nitrogen Monoxide (NO), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of NO - */ - public double getNitrogenMonoxide() { - checkForDataReadiness(Set.of("air_pollution")); - return getNitrogenMonoxide(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Nitrogen Monoxide (NO), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of NO at the requested timestamp - */ - public double getNitrogenMonoxide(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "no"); - } - - /** - * <p>Provides the current concentration of Nitrogen Dioxide (NO2), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of NO2 - */ - public double getNitrogenDioxide() { - checkForDataReadiness(Set.of("air_pollution")); - return getNitrogenDioxide(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Nitrogen Dioxide (NO2), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of NO2 at the requested timestamp - */ - public double getNitrogenDioxide(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "no2"); - } - - /** - * <p>Provides the current concentration of Ozone (O3), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of O3 - */ - public double getOzone() { - checkForDataReadiness(Set.of("air_pollution")); - return getOzone(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Ozone (O3), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of O3 at the requested timestamp - */ - public double getOzone(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "o3"); - } - - /** - * <p>Provides the current concentration of Sulfur Dioxide (SO2), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of SO2 - */ - public double getSulfurDioxide() { - checkForDataReadiness(Set.of("air_pollution")); - return getSulfurDioxide(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Sulfur Dioxide (SO2), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of SO2 at the requested timestamp - */ - public double getSulfurDioxide(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "so2"); - } - - /** - * <p>Provides the current concentration of Fine Particulate Matter (PM2.5), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of PM2.5 - */ - public double getFineParticulateMatter() { - checkForDataReadiness(Set.of("air_pollution")); - return getFineParticulateMatter(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Fine Particulate Matter (PM2.5), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of PM2.5 at the requested timestamp - */ - public double getFineParticulateMatter(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "pm2_5"); - } - - /** - * <p>Provides the current concentration of Coarse Particulate Matter (PM10), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of PM10 - */ - public double getCoarseParticulateMatter() { - checkForDataReadiness(Set.of("air_pollution")); - return getCoarseParticulateMatter(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Coarse Particulate Matter (PM10), in - * μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of PM10 at the requested timestamp - */ - public double getCoarseParticulateMatter(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "pm10"); - } - - /** - * <p>Provides the current concentration of Ammonia (NH3), in μg/m3</p> - * <p>Available for the "air_pollution" dataset.</p> - * - * @return current concentration of NH3 - */ - public double getAmmonia() { - checkForDataReadiness(Set.of("air_pollution")); - return getAmmonia(currentTimestamp); - } - - /** - * <p>Provides the current, historical, or forecasted concentration of Ammonia (NH3), in μg/m3</p> - * <p>Available for the "air_pollution", "air_pollution/history" and "air_pollution/forecast" datasets.</p> - * - * @param timestamp the date/time corresponding to the desired data - * @return concentration of NH3 at the requested timestamp - */ - public double getAmmonia(Date timestamp) { - checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); - return getPollutionData(timestamp, "nh3"); - } + /** + * <p> + * Top-level weather categories that may be reported in OpenWeather data. + * </p> + * + * <p> + * (n.b., {@link WeatherCategory#UNKNOWN_CATEGORY} is a catch-all for any + * reported categories that are not a documented weather condition.) + * </p> + * + * @see <a href="https://openweathermap.org/weather-conditions">OpenWeathermap + * Weather Conditions</a> + */ + public enum WeatherCategory { + UNKNOWN_CATEGORY, + THUNDERSTORM, // Group 2xx + DRIZZLE, // Group 3xx + RAIN, // Group 5xx + SNOW, // Group 6xx + // Group 7xx (Atmosphere) + MIST, // 701 + SMOKE, // 711 + HAZE, // 721 + DUST, // 731, 761 + FOG, // 741 + SAND, // 751 + ASH, // 762 + SQUALL, // 771 + TORNADO, // 781 + CLEAR, // Group 800 + CLOUDS, // Group 80x + } + + /** + * <p> + * Air Quality Indices reported in OpenWeather air pollution reports. Note that + * while openweathermap.org refers to the Air Quality Indices on a scale of Good + * (1) to Very Poor (5), the CAQI Air Quality Index report refers to the Air + * Quality Indices as a level of pollutants on a scale of Very Low (1) to Very + * High (5). Numerically they are equivalent but the English-language meaning is + * different. This enumerated type uses the CAQI nomenclature. + * </p> + * + * <p> + * (n.b., {@link AirQuality#UNKNOWN_AIR_QUALITY} is a catch-all when no air + * quality data is present.) + * </p> + * + * @see <a href="https://openweathermap.org/api/air-pollution">OpenWeathermap + * Air Pollution API</a> + * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality + * Index entry on Wikipedia</a> + * @see <a href= + * "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI + * Air Quality Index</a> + */ + public enum AirQuality { + UNKNOWN_AIR_QUALITY, VERY_LOW, // aqi==1 "Good" in openweathermap.org/api/air-pollution + LOW, // aqi==2 "Fair" in openweathermap.org/api/air-pollution + MEDIUM, // aqi==3 "Moderate" in openweathermap.org/api/air-pollution + HIGH, // aqi==4 "Poor" in openweathermap.org/api/air-pollution + VERY_HIGH, // aqi==5 "Very Poor" in openweathermap.org/api/air-pollution + } + + /** + * Supported data sets, a subset of the documented OpenWeathermap APIs. + */ + public static final Set<String> allowableDataSets = Set.of("weather", "onecall", "onecall/timemachine", "forecast", + "air_pollution", "air_pollution/forecast", "air_pollution/history", "direct", "reverse" // geocoding + // "stations", "triggers" excluded because PUT/POST calls are not supported here + // "map" excluded because it isn't JSON and also appears not to be a REST call + ); + + public static final Date IMPOSSIBLE_DATE = new Date(Long.MIN_VALUE); + public static final String PROTOCOL = "http"; + public static final String REST_AUTHORITY = "api.openweathermap.org"; + + protected final Connection dataSource; + protected String dataSet; + protected String REST_PATH; // Should be able to declare this as final, but static analysis doesn't see that + + protected JSONObject data; + protected Date currentTimestamp; + + /** + * <p> + * Constructor to be used when connecting to OpenWeather data stored in a local + * file. + * </p> + * + * <p> + * <i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, + * the data set is of the form "air_pollution/forecast" and + * "air_pollution/history". + * </p> + * + * @param fileDataSet directory containing the specified file; must correspond + * to one of the <a href= + * "https://openweathermap.org/api">OpenWeathermap.org + * APIs</a> + * @throws IllegalArgumentException if {@code fileDataSet} does not correspond + * to an OpenWeathermap.org API + */ + public OpenWeatherConnector(String fileDataSet) throws IllegalArgumentException { + initializeFields(fileDataSet); + dataSource = new FileConnection(fileDataSet); + } + + /** + * <p> + * Constructor to be used when connecting to + * <a href="https://openweathermap.org">OpenWeathermap.org</a>s's REST API. + * </p> + * + * <p> + * <i>Note</i>: in the case of Air Pollution Forecast and Air Pollution History, + * the data set is of the form "air_pollution/forecast" and + * "air_pollution/history". + * </p> + * + * @param restDataSet specific <a href= + * "https://openweathermap.org/api">OpenWeathermap.org + * API</a> to be used + * @param apiKey token provided by <a href= + * "https://openweathermap.org">OpenWeathermap.org</a> to + * authenticate requester and grant appropriate privileges + * @throws IllegalArgumentException if {@code fileDataSet} does not correspond + * to an OpenWeathermap.org API + */ + public OpenWeatherConnector(String restDataSet, String apiKey) throws IllegalArgumentException { + initializeFields(restDataSet); + dataSource = new RestConnection(PROTOCOL, REST_AUTHORITY, REST_PATH + restDataSet, apiKey); + } + + private void initializeFields(String intendedDataSet) throws IllegalArgumentException { + if (!allowableDataSets.contains(intendedDataSet)) { + throw new IllegalArgumentException(intendedDataSet + " is not a valid data set."); + } + dataSet = intendedDataSet; + switch (dataSet) { + case "weather": + case "onecall": + case "onecall/timemachine": + case "forecast": + case "air_pollution": + case "air_pollution/forecast": + case "air_pollution/history": + REST_PATH = "/data/2.5/"; + break; + case "direct": + case "reverse": + REST_PATH = "/geo/1.0/"; + break; + default: + REST_PATH = "unknown"; + } + data = null; + currentTimestamp = null; + } + + /** + * Retrieves requested data from the data set. Must be called at least once + * (without data, the other methods have no data to work with). The data will be + * stored as part of the {@link OpenWeatherConnector} instance; however, the + * JSON string will also be returned. + * + * @param requestedData the data to be retrieved. If connected to the local file + * system, this is the name of the file with the data. If + * connected to <a href= + * "https://openweathermap.org">OpenWeathermap.org/api</a> + * 's REST API, this is the query string. + * @return JSON string for the requested data + * @throws IOException if the data cannot be retrieved + */ + public String retrieveData(String requestedData) throws IOException { + try { + data = dataSource.get(requestedData); + } catch (FileNotFoundException fileNotFoundException) { + if (dataSource instanceof RestConnection) { + throw new IOException("Could not access \"" + dataSet + "\" dataset at " + REST_AUTHORITY + ".", + fileNotFoundException); + } else { + throw fileNotFoundException; // For FileConnection, this exception is exactly what's on the label, + } // except that we'd more likely see a NullPointerException... + } catch (NullPointerException nullPointerException) { + if (dataSource instanceof FileConnection) { + FileNotFoundException newException = new FileNotFoundException("File " + requestedData + " not found."); + newException.initCause(nullPointerException); + throw newException; + } else { + throw nullPointerException; // Not going to try to predict why RestConnection generates NPE + } + } catch (ParseException parseException) { + String message; + if (dataSource instanceof FileConnection) { + message = "Error while parsing file " + requestedData + "."; + } else if (dataSource instanceof RestConnection) { + message = "Error while parsing the " + dataSet + " response from " + REST_AUTHORITY + "."; + } else { + message = "Error while parsing requested data."; + } + throw new IOException(message, parseException); + } + checkForDataReadiness(null); + long unixTime = extractLongFromJSON(data, "dt", extractLongFromJSON(data, "current", "dt", Long.MIN_VALUE)); + if (unixTime == Long.MIN_VALUE && data.containsKey("list") && ((JSONArray) data.get("list")).size() == 1) { + // this is how current air quality data is reported + unixTime = (Long) ((JSONObject) ((JSONArray) data.get("list")).get(0)).get("dt"); + } + currentTimestamp = unixTime == Long.MIN_VALUE ? IMPOSSIBLE_DATE : new Date(unixTime * 1000); + return data.toJSONString(); + } + + /* + * Helper Methods + */ + + /** + * Checks whether {@link #data} was populated by calling + * {@link #retrieveData(String)} and whether the calling method can use the + * dataset specified in the constructor call. + * + * @param supportedDataSets the datasets that are relevant to the calling method + * or {@code null} if all datasets are relevant + * @throws IllegalStateException if no data has been retrieved using + * {@link #retrieveData(String)} + * @throws UnsupportedOperationException if the dataset specified in the + * constructor call does not apply to the + * method that called + * {@code checkForDataPresence(Set)} + */ + private void checkForDataReadiness(Set<String> supportedDataSets) + throws IllegalStateException, UnsupportedOperationException { + if (data == null) { + throw new IllegalStateException("No data has been retrieved from the " + dataSet + " dataset."); + } + if (supportedDataSets != null && !supportedDataSets.contains(dataSet)) { + throw new UnsupportedOperationException("Attempted to call method on an inapplicable dataset (" + dataSet + + "). Applicable dataset(s): " + supportedDataSets + "."); + } + } + + /** + * Returns value associated with the key in the JSON object. The caller is + * responsible for making sure that the JSON object is not null; however, the + * caller does <i>not</i> need to establish that the key is present. Returns the + * default value if the key is not present. + * + * @param jsonObject JSON object that may contain the key and value of + * interest + * @param key the key of interest + * @param defaultValue the value to be returned if the key is not present + * @return the value of interest, or the default value if the key is not present + */ + private double extractDoubleFromJSON(JSONObject jsonObject, String key, double defaultValue) { + double returnValue = defaultValue; + if (jsonObject.containsKey(key)) { + Number value = (Number) jsonObject.get(key); + returnValue = value == null ? defaultValue : value.doubleValue(); + } + return returnValue; + } + + /** + * Returns value associated with the key in a second-level JSON object in the + * specified JSON object. The caller is responsible for making sure that the + * JSON object is not null; however, the caller does <i>not</i> need to + * establish that the key is present. Returns the default value if the key is + * not present. + * + * @param jsonObject JSON object that may contain the key and value of + * interest + * @param topLevelField the key to access the second-level JSON object + * @param subField the key of interest in the second-level JSON object + * @param defaultValue the value to be returned if the key is not present + * @return the value of interest, or the default value if the key is not present + */ + private double extractDoubleFromJSON(JSONObject jsonObject, String topLevelField, String subField, + double defaultValue) { + double returnValue = defaultValue; + if (jsonObject.containsKey(topLevelField)) { + JSONObject secondLevelJsonObject = (JSONObject) jsonObject.get(topLevelField); + returnValue = extractDoubleFromJSON(secondLevelJsonObject, subField, defaultValue); + } + return returnValue; + } + + /** + * Returns value associated with the key in the JSON object. The caller is + * responsible for making sure that the JSON object is not null; however, the + * caller does <i>not</i> need to establish that the key is present. Returns the + * default value if the key is not present. + * + * @param jsonObject JSON object that may contain the key and value of + * interest + * @param key the key of interest + * @param defaultValue the value to be returned if the key is not present + * @return the value of interest, or the default value if the key is not present + */ + private long extractLongFromJSON(JSONObject jsonObject, String key, long defaultValue) { + long returnValue = defaultValue; + if (jsonObject.containsKey(key)) { + Long value = (Long) jsonObject.get(key); + returnValue = value == null ? defaultValue : value; + } + return returnValue; + } + + /** + * Returns value associated with the key in a second-level JSON object in the + * specified JSON object. The caller is responsible for making sure that the + * JSON object is not null; however, the caller does <i>not</i> need to + * establish that the key is present. Returns the default value if the key is + * not present. + * + * @param jsonObject JSON object that may contain the key and value of + * interest + * @param topLevelField the key to access the second-level JSON object + * @param subField the key of interest in the second-level JSON object + * @param defaultValue the value to be returned if the key is not present + * @return the value of interest, or the default value if the key is not present + */ + private long extractLongFromJSON(JSONObject jsonObject, String topLevelField, String subField, long defaultValue) { + long returnValue = defaultValue; + if (jsonObject.containsKey(topLevelField)) { + JSONObject secondLevelJsonObject = (JSONObject) jsonObject.get(topLevelField); + returnValue = extractLongFromJSON(secondLevelJsonObject, subField, defaultValue); + } + return returnValue; + } + + /** + * Returns object in the list associated with the key, at the specified + * timestamp. Returns null if the list is not present, or if there is no list + * entry at the timestamp. + * + * @param listName the key to access the list + * @param timestamp the timestamp of the list entry + * @return the object of interest, or null if the list or the timestamp are not + * present + */ + private JSONObject getListEntry(String listName, Date timestamp) { + JSONObject listEntry = null; + if (data.containsKey(listName)) { + JSONArray list = (JSONArray) data.get(listName); + for (Object entry : list) { + if ((Long) ((JSONObject) entry).get("dt") == timestamp.getTime() / 1000) { + listEntry = (JSONObject) entry; + } + } + } + return listEntry; + } + + /* + * Wrapper methods for all reports + */ + + /** + * <p> + * Provides the latitude for the weather's location. + * </p> + * <p> + * Available for all datasets. + * </p> + * + * @return location's latitude + */ + public double getLatitude() { + checkForDataReadiness(null); + JSONObject locationContainer = data; + if (data.containsKey("city")) { + locationContainer = (JSONObject) data.get("city"); + } + if (dataSet.startsWith("onecall")) { + return extractDoubleFromJSON(locationContainer, "lat", Double.NaN); + } else { + return extractDoubleFromJSON(locationContainer, "coord", "lat", Double.NaN); + } + } + + /** + * <p> + * Provides the longitude for the weather's location. + * </p> + * <p> + * Available for all datasets. + * </p> + * + * @return location's longitude + */ + public double getLongitude() { + checkForDataReadiness(null); + JSONObject locationContainer = data; + if (data.containsKey("city")) { + locationContainer = (JSONObject) data.get("city"); + } + if (dataSet.startsWith("onecall")) { + return extractDoubleFromJSON(locationContainer, "lon", Double.NaN); + } else { + return extractDoubleFromJSON(locationContainer, "coord", "lon", Double.NaN); + } + } + + /** + * <p> + * Provides the date and time for the current weather, or + * {@link #IMPOSSIBLE_DATE} if no valid timestamp exists. + * </p> + * <p> + * Available for all datasets with data for the present. + * </p> + * + * @return timestamp for the weather observations + */ + public Date getTimestamp() { + checkForDataReadiness(null); + return currentTimestamp; + } + + /** + * Extracts epoch-based timestamps from the specified JSON list and places + * {@link Date} timestamps into the provided {@link List}. + * + * @param jsonListName the name of the JSON list containing data with timestamps + * @param timestamps the possibly-nonempty {@link List} to place the + * {@link Date} timestamps in + */ + private void moveTimestampsFromJsonArrayToJavaList(String jsonListName, List<Date> timestamps) { + if (data.containsKey(jsonListName)) { + JSONArray entries = (JSONArray) data.get(jsonListName); + if (entries != null) { + for (Object entry : entries) { + long unixTime = (Long) ((JSONObject) entry).get("dt"); + timestamps.add(new Date(unixTime * 1000)); + } + } + } + } + + /** + * <p> + * Provides all dates and times for reports with multiple timestamps. + * </p> + * <p> + * Available for all datasets with data in the past or the future. + * </p> + * + * @return list of timestamps for the weather observations + */ + public List<Date> getTimestamps() { + checkForDataReadiness(null); + Set<String> possibleListNames = Set.of("list", "minutely", "hourly", "daily"); + List<Date> timestamps = new ArrayList<>(); + for (String listName : possibleListNames) { + moveTimestampsFromJsonArrayToJavaList(listName, timestamps); + } + timestamps.sort(null); + return List.copyOf(timestamps); + } + + /** + * <p> + * Provides the dates and times for a specific list, for reports with multiple + * timestamps. + * </p> + * <p> + * Available for all datasets with data in the past or the future. + * </p> + * + * @param listName the name of the list whose timestamps are of interest + * @return list of timestamps for the weather observations + */ + public List<Date> getTimestamps(String listName) { + checkForDataReadiness(null); + List<Date> timestamps = new ArrayList<>(); + moveTimestampsFromJsonArrayToJavaList(listName, timestamps); + timestamps.sort(null); + return List.copyOf(timestamps); + } + + /* + * Wrapper methods for current and forecasted weather + */ + + /** + * <p> + * Provides the broad categories for the weather reported in the provided JSON + * object. If there are more than one category provided, the "primary" category + * will at the head of the list. The weather categories are guaranteed to be in + * the same order as the corresponding descriptions provided by + * {@link #getWeatherDescriptions()}. + * </p> + * <p> + * The caller is responsible for ensuring that data is present. + * </p> + * + * @param jsonObject the object containing the weather data + * @return list of weather categories + * @see #getWeatherDescriptions() + */ + private List<WeatherCategory> getWeatherCategories(JSONObject jsonObject) { + JSONArray weather = (JSONArray) jsonObject.get("weather"); + List<WeatherCategory> categories; + if (weather != null) { + categories = new ArrayList<>(weather.size()); + for (Object condition : weather) { + String category = ((JSONObject) condition).get("main").toString(); + try { + categories.add(WeatherCategory.valueOf(category.toUpperCase())); + } catch (IllegalArgumentException ignored) { + categories.add(WeatherCategory.UNKNOWN_CATEGORY); + } + } + } else { + categories = new ArrayList<>(0); + } + return List.copyOf(categories); + } + + /** + * <p> + * Provides the broad categories for the current weather. If there are more than + * one category provided, the "primary" category will at the head of the list. + * The weather categories are guaranteed to be in the same order as the + * corresponding descriptions provided by {@link #getWeatherDescriptions()}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return list of weather categories + * @see #getWeatherDescriptions() + */ + public List<WeatherCategory> getWeatherCategories() { + checkForDataReadiness(Set.of("weather", "onecall")); + return getWeatherCategories(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data); + } + + /** + * <p> + * Provides the broad categories for the forecasted weather. If there are more + * than one category provided, the "primary" category will at the head of the + * list. The weather categories are guaranteed to be in the same order as the + * corresponding descriptions provided by {@link #getWeatherDescriptions()}. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return list of forecasted weather categories + * @see #getWeatherDescriptions() + */ + public List<WeatherCategory> getWeatherCategories(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + String listName = "list"; + if (dataSet.equals("onecall")) { + List<Date> hours = getTimestamps("hourly"); + listName = hours.contains(timestamp) ? "hourly" : "daily"; + } + return getWeatherCategories(getListEntry(listName, timestamp)); + } + + /** + * <p> + * Provides descriptions of the weather reported in the provided JSON object. If + * there are more than one weather description provided, the "primary" + * description will be at the head of the list. The weather descriptions are + * guaranteed to be in the same order as the corresponding categories provided + * by {@link #getWeatherCategories()}. + * </p> + * <p> + * The caller is responsible for ensuring that data is present. + * </p> + * + * @param jsonObject the object containing the weather data + * @return list of weather descriptions + * @see #getWeatherCategories() + */ + private List<String> getWeatherDescriptions(JSONObject jsonObject) { + JSONArray weather = (JSONArray) jsonObject.get("weather"); + List<String> descriptions; + if (weather != null) { + descriptions = new ArrayList<>(weather.size()); + for (Object condition : weather) { + descriptions.add(((JSONObject) condition).get("description").toString()); + } + } else { + descriptions = new ArrayList<>(0); + } + return List.copyOf(descriptions); + } + + /** + * <p> + * Provides descriptions of the current weather. If there are more than one + * weather description provided, the "primary" description will be at the head + * of the list. The weather descriptions are guaranteed to be in the same order + * as the corresponding categories provided by {@link #getWeatherCategories()}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return list of weather descriptions + * @see #getWeatherCategories() + */ + public List<String> getWeatherDescriptions() { + checkForDataReadiness(Set.of("weather", "onecall")); + return getWeatherDescriptions(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data); + } + + /** + * <p> + * Provides descriptions of the forecasted weather. If there are more than one + * weather description provided, the "primary" description will be at the head + * of the list. The weather descriptions are guaranteed to be in the same order + * as the corresponding categories provided by {@link #getWeatherCategories()}. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return list of forecasted weather descriptions + * @see #getWeatherCategories() + */ + public List<String> getWeatherDescriptions(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + String listName = "list"; + if (dataSet.equals("onecall")) { + List<Date> hours = getTimestamps("hourly"); + listName = hours.contains(timestamp) ? "hourly" : "daily"; + } + return getWeatherDescriptions(getListEntry(listName, timestamp)); + } + + /** + * <p> + * Provides the current visibility in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current visibility, or {@link Long#MIN_VALUE} if visibility is + * not in current observation + */ + public long getVisibility() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractLongFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data, + "visibility", Long.MIN_VALUE); + } + + /** + * <p> + * Provides the forecasted visibility in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" (hourly only) datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted visibility, or {@link Long#MIN_VALUE} if visibility is + * not in the forecast + */ + public long getVisibility(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("onecall") && !getTimestamps("hourly").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); + } + String listName = dataSet.equals("onecall") ? "hourly" : "list"; + return extractLongFromJSON(getListEntry(listName, timestamp), "visibility", Long.MIN_VALUE); + } + + /** + * <p> + * Provides the current temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current temperature, or {@link Double#NaN} if temperature is not + * in current observation + */ + public double getTemperature() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractDoubleFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "temp", Double.NaN); + } + + /** + * <p> + * Provides the forecasted temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" (hourly only) datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted temperature, or {@link Double#NaN} if temperature is + * not in the forecast + */ + public double getTemperature(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "temp", Double.NaN); + } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) { + return extractDoubleFromJSON(getListEntry("hourly", timestamp), "temp", Double.NaN); + } else { + throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); + } + } + + /** + * <p> + * Provides the forecasted morning temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted morning temperature, or {@link Double#NaN} if morning + * temperature is not in the forecast + */ + public double getMorningTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "morn", Double.NaN); + } + + /** + * <p> + * Provides the forecasted daytime temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted daytime temperature, or {@link Double#NaN} if daytime + * temperature is not in the forecast + */ + public double getDaytimeTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "day", Double.NaN); + } + + /** + * <p> + * Provides the forecasted evening temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted evening temperature, or {@link Double#NaN} if evening + * temperature is not in the forecast + */ + public double getEveningTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "eve", Double.NaN); + } + + /** + * <p> + * Provides the forecasted nighttime temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted nighttime temperature, or {@link Double#NaN} if + * nighttime temperature is not in the forecast + */ + public double getNighttimeTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "night", Double.NaN); + } + + /** + * <p> + * Provides the forecasted daily low temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted daily low temperature, or {@link Double#NaN} if daily + * low temperature is not in the forecast + */ + public double getLowTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "min", Double.NaN); + } + + /** + * <p> + * Provides the forecasted daily high temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted daily high temperature, or {@link Double#NaN} if daily + * high temperature is not in the forecast + */ + public double getHighTemperature(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "temp", "max", Double.NaN); + } + + /** + * <p> + * Provides the current relative humidity (percent of saturation). + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current humidity, or {@link Long#MIN_VALUE} if visibility is not + * in current observation + */ + public long getHumidity() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractLongFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "humidity", + Long.MIN_VALUE); + } + + /** + * <p> + * Provides the forecasted relative humidity (percent of saturation). + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted humidity, or {@link Long#MIN_VALUE} if visibility is + * not in the forecast + */ + public long getHumidity(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractLongFromJSON(getListEntry("list", timestamp), "main", "humidity", Long.MIN_VALUE); + } else if (dataSet.equals("onecall")) { + return extractLongFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), + "humidity", Long.MIN_VALUE); + } else { + return Long.MIN_VALUE; + } + } + + /** + * <p> + * Provides the current dew point in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @return the current dew point, or {@link Double#NaN} if dew point is not in + * current observation + */ + public double getDewPoint() { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON(data, "current", "dew_point", Double.NaN); + } + + /** + * <p> + * Provides the forecasted dew point in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted dew point, or {@link Double#NaN} if dew point is not + * in the forecast + */ + public double getDewPoint(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "dew_point", + Double.NaN); + } + + /** + * <p> + * Provides the current "feels like" temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current "feels like" temperature, or {@link Double#NaN} if "feels + * like" temperature is not in current observation + */ + public double getFeelsLike() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractDoubleFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "feels_like", + Double.NaN); + } + + /** + * <p> + * Provides the forecasted "feels like" temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" (hourly only) datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted "feels like" temperature, or {@link Double#NaN} if + * "feels like" temperature is not in the forecast + */ + public double getFeelsLike(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractDoubleFromJSON(getListEntry("list", timestamp), "main", "feels_like", Double.NaN); + } else if (dataSet.equals("onecall") && getTimestamps("hourly").contains(timestamp)) { + return extractDoubleFromJSON(getListEntry("hourly", timestamp), "feels_like", Double.NaN); + } else { + throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); + } + } + + /** + * <p> + * Provides the forecasted morning "feels like" temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted morning "feels like" temperature, or + * {@link Double#NaN} if morning "feels like" temperature is not in the + * forecast + */ + public double getMorningFeelsLike(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "morn", Double.NaN); + } + + /** + * <p> + * Provides the forecasted "feels like" daytime temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted daytime "feels like" temperature, or + * {@link Double#NaN} if daytime "feels like" temperature is not in the + * forecast + */ + public double getDaytimeFeelsLike(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "day", Double.NaN); + } + + /** + * <p> + * Provides the forecasted evening "feels like" temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted evening "feels like" temperature, or + * {@link Double#NaN} if evening "feels like" temperature is not in the + * forecast + */ + public double getEveningFeelsLike(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "eve", Double.NaN); + } + + /** + * <p> + * Provides the forecasted nighttime "feels like" temperature in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "onecall" (daily only) dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted nighttime "feels like" temperature, or + * {@link Double#NaN} if nighttime "feels like" temperature is not in + * the forecast + */ + public double getNighttimeFeelsLike(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("daily").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for daily timestamps."); + } + return extractDoubleFromJSON(getListEntry("daily", timestamp), "feels_like", "night", Double.NaN); + } + + /** + * <p> + * Provides the current pressure in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current pressure, or {@link Long#MIN_VALUE} if pressure is not in + * current observation + */ + public long getPressure() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractLongFromJSON(data, dataSet.startsWith("onecall") ? "current" : "main", "pressure", + Long.MIN_VALUE); + } + + /** + * <p> + * Provides the forecasted pressure in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted pressure, or {@link Long#MIN_VALUE} if pressure is not + * in the forecast + */ + public long getPressure(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractLongFromJSON(getListEntry("list", timestamp), "main", "pressure", Long.MIN_VALUE); + } else if (dataSet.equals("onecall")) { + return extractLongFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), + "pressure", Long.MIN_VALUE); + } else { + return Long.MIN_VALUE; + } + } + + /** + * <p> + * Provides the current wind direction, in degrees. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current wind direction, or {@link Long#MIN_VALUE} if winds are + * not in current observation + */ + public long getWindDirection() { + checkForDataReadiness(Set.of("weather", "onecall")); + if (dataSet.startsWith("onecall")) { + return extractLongFromJSON(data, "current", "wind_deg", Long.MIN_VALUE); + } else { + return extractLongFromJSON(data, "wind", "deg", Long.MIN_VALUE); + } + } + + /** + * <p> + * Provides the forecasted wind direction, in degrees. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted wind direction, or {@link Long#MIN_VALUE} if winds are + * not in the forecast + */ + public long getWindDirection(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractLongFromJSON(getListEntry("list", timestamp), "wind", "deg", Long.MIN_VALUE); + } else if (dataSet.equals("onecall")) { + return extractLongFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), + "wind_deg", Long.MIN_VALUE); + } else { + return Long.MIN_VALUE; + } + } + + /** + * <p> + * Provides the current wind speed in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current wind speed, or 0.0 if winds are not in current + * observation + */ + public double getWindSpeed() { + checkForDataReadiness(Set.of("weather", "onecall")); + if (dataSet.startsWith("onecall")) { + return extractDoubleFromJSON(data, "current", "wind_speed", 0.0); + } else { + return extractDoubleFromJSON(data, "wind", "speed", 0.0); + } + } + + /** + * <p> + * Provides the forecasted wind speed in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted wind speed, or 0.0 if winds are not in the forecast + */ + public double getWindSpeed(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "speed", 0.0); + } else if (dataSet.equals("onecall")) { + return extractDoubleFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), + "wind_speed", 0.0); + } else { + return 0.0; + } + } + + /** + * <p> + * Provides the current wind gust in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current wind gust, or current wind speed if wind gust is not in + * current observation + */ + public double getWindGust() { + checkForDataReadiness(Set.of("weather", "onecall")); + if (dataSet.startsWith("onecall")) { + return extractDoubleFromJSON(data, "current", "wind_gust", getWindSpeed()); + } else { + return extractDoubleFromJSON(data, "wind", "gust", getWindSpeed()); + } + } + + /** + * <p> + * Provides the forecasted wind gust in the default + * <a href="https://openweathermap.org/current#data">units</a> or those + * specified in the call to {@link #retrieveData(String)}. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted wind gust, or current wind speed if wind gust is not + * in the forecast + */ + public double getWindGust(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.equals("forecast")) { + return extractDoubleFromJSON(getListEntry("list", timestamp), "wind", "gust", getWindSpeed(timestamp)); + } else if (dataSet.equals("onecall")) { + return extractDoubleFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), + "wind_gust", getWindSpeed(timestamp)); + } else { + return getWindSpeed(timestamp); + } + } + + /** + * <p> + * Provides the current UV Index. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @return the current UV Index, or {@link Double#NaN} if the UV Index is not in + * current observation + */ + public double getUltravioletIndex() { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON(data, "current", "uvi", Double.NaN); + } + + /** + * <p> + * Provides the forecasted UV Index. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted UV Index, or {@link Double#NaN} if the UV Index is not + * in the forecast + */ + public double getUltravioletIndex(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "uvi", + Double.NaN); + } + + /** + * <p> + * Provides the current cloud cover percentage (cloudiness). + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current cloudiness, or 0 if cloudiness is not in current + * observation + */ + public long getCloudCover() { + checkForDataReadiness(Set.of("weather", "onecall")); + if (dataSet.startsWith("onecall")) { + return extractLongFromJSON(data, "clouds", 0); + } else { + return extractLongFromJSON(data, "clouds", "all", 0); + } + } + + /** + * <p> + * Provides the forecasted cloud cover percentage (cloudiness). + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted cloudiness, or 0 if cloudiness is not in current + * observation + */ + public long getCloudCover(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + if (dataSet.startsWith("onecall")) { + return extractLongFromJSON( + getListEntry(getTimestamps("hourly").contains(timestamp) ? "hourly" : "daily", timestamp), "clouds", + 0); + } else { + return extractLongFromJSON(getListEntry("list", timestamp), "clouds", "all", 0); + } + } + + /** + * <p> + * Provides the forecasted probability of rain, on a 0.0-1.0 scale. + * </p> + * <p> + * Available for the "forecast" and "onecall" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return the forecasted probability of precipitation, or NaN if cloudiness is + * not in current observation + */ + public double getProbabilityOfPrecipitation(Date timestamp) { + checkForDataReadiness(Set.of("forecast", "onecall")); + String listName = "list"; + if (dataSet.equals("onecall")) { + List<Date> hours = getTimestamps("hourly"); + listName = hours.contains(timestamp) ? "hourly" : "daily"; + } + return extractDoubleFromJSON(getListEntry(listName, timestamp), "pop", Double.NaN); + } + + /** + * <p> + * Provides the one-hour rainfall total column, in millimeters. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current one-hour rainfall total, or 0.0 if rain volume is not in + * current observation + */ + public double getOneHourRainfall() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data, "rain", + "1h", 0.0); + } + + /** + * <p> + * Provides the total rain column, in millimeters, forecasted for the one hour + * before the specified timestamp. + * </p> + * <p> + * Available for the "onecall" (hourly only) dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted rainfall + * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not + * in the forecast + */ + public double getOneHourRainfall(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("hourly").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); + } + return extractDoubleFromJSON(getListEntry("hourly", timestamp), "rain", "1h", 0.0); + } + + /** + * <p> + * Provides the three-hour rainfall total column, in millimeters. + * </p> + * <p> + * Available for the "weather" dataset. + * </p> + * + * @return the current three-hour rainfall total, or 0.0 if rain volume is not + * in current observation + */ + public double getThreeHourRainfall() { + checkForDataReadiness(Set.of("weather")); + return extractDoubleFromJSON(data, "rain", "3h", getOneHourRainfall()); + } + + /** + * <p> + * Provides the total rain column, in millimeters, forecasted for the three + * hours before the specified timestamp. + * </p> + * <p> + * Available for the "forecast" dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted rainfall + * @return the forecasted three-hour rainfall total, or 0.0 if rain volume is + * not in the forecast + */ + public double getThreeHourRainfall(Date timestamp) { + checkForDataReadiness(Set.of("forecast")); + return extractDoubleFromJSON(getListEntry("list", timestamp), "rain", "3h", 0.0); + } + + /** + * <p> + * Provides the one-hour snowfall total column, in millimeters. + * </p> + * <p> + * Available for the "weather" and "onecall" datasets. + * </p> + * + * @return the current one-hour snowfall total, or 0.0 if snow volume is not in + * current observation + */ + public double getOneHourSnowfall() { + checkForDataReadiness(Set.of("weather", "onecall")); + return extractDoubleFromJSON(dataSet.startsWith("onecall") ? (JSONObject) data.get("current") : data, "snow", + "1h", 0.0); + } + + /** + * <p> + * Provides the total snow column, in millimeters, forecasted for the one hour + * before the specified timestamp. + * </p> + * <p> + * Available for the "onecall" (hourly only) dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted snowfall + * @return the forecasted one-hour rainfall total, or 0.0 if rain volume is not + * in the forecast + */ + public double getOneHourSnowfall(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("hourly").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for hourly timestamps."); + } + return extractDoubleFromJSON(getListEntry("hourly", timestamp), "snow", "1h", 0.0); + } + + /** + * <p> + * Provides the three-hour snowfall total column, in millimeters. + * </p> + * <p> + * Available for the "weather" dataset. + * </p> + * + * @return the current three-hour snowfall total, or 0.0 if snow volume is not + * in current observation + */ + public double getThreeHourSnowfall() { + checkForDataReadiness(Set.of("weather")); + return extractDoubleFromJSON(data, "snow", "3h", getOneHourSnowfall()); + } + + /** + * <p> + * Provides the total snow column, in millimeters, forecasted for the three + * hours before the specified timestamp. + * </p> + * <p> + * Available for the "forecast" dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted snowfall + * @return the forecasted three-hour snowfall total, or 0.0 if snow volume is + * not in the forecast + */ + public double getThreeHourSnowfall(Date timestamp) { + checkForDataReadiness(Set.of("forecast")); + return extractDoubleFromJSON(getListEntry("list", timestamp), "snow", "3h", 0.0); + } + + /** + * <p> + * Provides the precipitation column, in millimeters, forecasted for the the + * specified minute. Not explicitly stated in the API specification, this + * appears to be a 1-hour total that does not distinguish between rain and snow. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted precipitation + * @return the forecasted precipitation total, or 0.0 if precipitation volume is + * not in the forecast + */ + public double getMinutelyPrecipitation(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + if (!getTimestamps("minutely").contains(timestamp)) { + throw new UnsupportedOperationException("This onecall datum is only available for minutely timestamps."); + } + return extractDoubleFromJSON(getListEntry("minutely", timestamp), "precipitation", 0.0); + } + + /** + * <p> + * Provides the rain column, in millimeters, forecasted for the the specified + * day. Not explicitly stated in the API specification, this appears to be a + * daily total. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted rainfall + * @return the forecasted rain total, or 0.0 if precipitation volume is not in + * the forecast + */ + public double getDailyRainfall(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON(getListEntry("daily", timestamp), "rain", 0.0); + } + + /** + * <p> + * Provides the snow column, in millimeters, forecasted for the the specified + * day. Not explicitly stated in the API specification, this appears to be a + * daily total. + * </p> + * <p> + * Available for the "onecall" dataset. + * </p> + * + * @param timestamp the timestamp for the forecasted snowfall + * @return the forecasted snow total, or 0.0 if precipitation volume is not in + * the forecast + */ + public double getDailySnowfall(Date timestamp) { + checkForDataReadiness(Set.of("onecall")); + return extractDoubleFromJSON(getListEntry("daily", timestamp), "snow", 0.0); + } + + /* + * Wrapper methods for Air Quality + */ + + /** + * Returns the concentration for the specified pollutant at the specified + * timestamp from the list of air quality entries. + * + * @param timestamp the timestamp for the air quality entry + * @param pollutant the pollutant whose concentration is to be obtained + * @return the value associated with the specified pollutant at the specified + * timestamp + */ + private double getPollutionData(Date timestamp, String pollutant) { + JSONObject currentEntry = getListEntry("list", timestamp); + if (currentEntry == null) { + return Double.NaN; + } else { + return extractDoubleFromJSON(currentEntry, "components", pollutant, Double.NaN); + } + } + + /** + * <p> + * Provides the current basic Air Quality Index, using the European CAQI tables. + * This is a composite metric based on concentrations of nitrogen monoxide, + * ozone, coarse particulates, and optionally fine particulates. + * </p> + * + * <p> + * The air quality is reported on a range from {@link AirQuality#VERY_LOW} + * (good) to {@link AirQuality#VERY_HIGH} (very poor) + * </p> + * + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return air quality index at the requested timestamp + * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality + * Index entry on Wikipedia</a> + * @see <a href= + * "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI + * Air Quality Index</a> + */ + public AirQuality getAirQualityIndex() { + checkForDataReadiness(Set.of("air_pollution")); + return getAirQualityIndex(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted basic Air Quality Index, + * using the European CAQI tables. This is a composite metric based on + * concentrations of nitrogen monoxide, ozone, coarse particulates, and + * optionally fine particulates. + * </p> + * + * <p> + * The air quality is reported on a range from {@link AirQuality#VERY_LOW} + * (good) to {@link AirQuality#VERY_HIGH} (very poor) + * </p> + * + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return air quality index at the requested timestamp + * @see <a href="https://en.wikipedia.org/wiki/Air_quality_index">Air Quality + * Index entry on Wikipedia</a> + * @see <a href= + * "https://www.airqualitynow.eu/download/CITEAIR-Comparing_Urban_Air_Quality_across_Borders.pdf">CAQI + * Air Quality Index</a> + */ + public AirQuality getAirQualityIndex(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + JSONObject currentEntry = getListEntry("list", timestamp); + int airQualityIndex = 0; + if (currentEntry != null) { + airQualityIndex = (int) extractLongFromJSON(currentEntry, "main", "aqi", 0); + } + return AirQuality.values()[airQualityIndex]; + } + + /** + * <p> + * Provides the current concentration of Carbon Monoxide (CO), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of CO + */ + public double getCarbonMonoxide() { + checkForDataReadiness(Set.of("air_pollution")); + return getCarbonMonoxide(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Carbon + * Monoxide (CO), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of CO at the requested timestamp + */ + public double getCarbonMonoxide(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "co"); + } + + /** + * <p> + * Provides the current concentration of Nitrogen Monoxide (NO), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of NO + */ + public double getNitrogenMonoxide() { + checkForDataReadiness(Set.of("air_pollution")); + return getNitrogenMonoxide(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Nitrogen + * Monoxide (NO), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of NO at the requested timestamp + */ + public double getNitrogenMonoxide(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "no"); + } + + /** + * <p> + * Provides the current concentration of Nitrogen Dioxide (NO2), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of NO2 + */ + public double getNitrogenDioxide() { + checkForDataReadiness(Set.of("air_pollution")); + return getNitrogenDioxide(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Nitrogen + * Dioxide (NO2), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of NO2 at the requested timestamp + */ + public double getNitrogenDioxide(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "no2"); + } + + /** + * <p> + * Provides the current concentration of Ozone (O3), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of O3 + */ + public double getOzone() { + checkForDataReadiness(Set.of("air_pollution")); + return getOzone(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Ozone (O3), + * in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of O3 at the requested timestamp + */ + public double getOzone(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "o3"); + } + + /** + * <p> + * Provides the current concentration of Sulfur Dioxide (SO2), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of SO2 + */ + public double getSulfurDioxide() { + checkForDataReadiness(Set.of("air_pollution")); + return getSulfurDioxide(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Sulfur + * Dioxide (SO2), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of SO2 at the requested timestamp + */ + public double getSulfurDioxide(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "so2"); + } + + /** + * <p> + * Provides the current concentration of Fine Particulate Matter (PM2.5), in + * μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of PM2.5 + */ + public double getFineParticulateMatter() { + checkForDataReadiness(Set.of("air_pollution")); + return getFineParticulateMatter(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Fine + * Particulate Matter (PM2.5), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of PM2.5 at the requested timestamp + */ + public double getFineParticulateMatter(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "pm2_5"); + } + + /** + * <p> + * Provides the current concentration of Coarse Particulate Matter (PM10), in + * μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of PM10 + */ + public double getCoarseParticulateMatter() { + checkForDataReadiness(Set.of("air_pollution")); + return getCoarseParticulateMatter(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Coarse + * Particulate Matter (PM10), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of PM10 at the requested timestamp + */ + public double getCoarseParticulateMatter(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "pm10"); + } + + /** + * <p> + * Provides the current concentration of Ammonia (NH3), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution" dataset. + * </p> + * + * @return current concentration of NH3 + */ + public double getAmmonia() { + checkForDataReadiness(Set.of("air_pollution")); + return getAmmonia(currentTimestamp); + } + + /** + * <p> + * Provides the current, historical, or forecasted concentration of Ammonia + * (NH3), in μg/m3 + * </p> + * <p> + * Available for the "air_pollution", "air_pollution/history" and + * "air_pollution/forecast" datasets. + * </p> + * + * @param timestamp the date/time corresponding to the desired data + * @return concentration of NH3 at the requested timestamp + */ + public double getAmmonia(Date timestamp) { + checkForDataReadiness(Set.of("air_pollution", "air_pollution/history", "air_pollution/forecast")); + return getPollutionData(timestamp, "nh3"); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java index 8ec2328..7c99d0a 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_UnlNov24ToNov27Test.java @@ -11,88 +11,89 @@ import java.util.List; import static org.junit.Assert.assertEquals; public class AirPollution_UnlNov24ToNov27Test { - private OpenWeatherConnector connector; - private List<Date> timestamps; + private OpenWeatherConnector connector; + private List<Date> timestamps; - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("air_pollution/history"); - connector.retrieveData("air_pollution-unl-historical.json"); - timestamps = connector.getTimestamps(); - } + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("air_pollution/history"); + connector.retrieveData("air_pollution-unl-historical.json"); + timestamps = connector.getTimestamps(); + } - @Test - public void testLocation() { - double expectedLatitude = 40.8151; - double expectedLongitude = -96.7049; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } + @Test + public void testLocation() { + double expectedLatitude = 40.8151; + double expectedLongitude = -96.7049; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } - @Test - public void testAirQualityIndex() { - // We'll pick one of the hours that has AQI==2 - OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.LOW; - OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(timestamps.get(25)); - assertEquals(expectedValue, actualValue); - } + @Test + public void testAirQualityIndex() { + // We'll pick one of the hours that has AQI==2 + OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.LOW; + OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(timestamps.get(25)); + assertEquals(expectedValue, actualValue); + } - @Test - public void testCO() { - double expectedValue = 240.33; - double actualValue = connector.getCarbonMonoxide(timestamps.get(0)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testCO() { + double expectedValue = 240.33; + double actualValue = connector.getCarbonMonoxide(timestamps.get(0)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testNO() { - // This is interesting. Normally a double, this report has NO as 0 instead of 0.0. - double expectedValue = 0.0; - double actualValue = connector.getNitrogenMonoxide(timestamps.get(1)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testNO() { + // This is interesting. Normally a double, this report has NO as 0 instead of + // 0.0. + double expectedValue = 0.0; + double actualValue = connector.getNitrogenMonoxide(timestamps.get(1)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testNO2() { - double expectedValue = 3.64; - double actualValue = connector.getNitrogenDioxide(timestamps.get(2)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testNO2() { + double expectedValue = 3.64; + double actualValue = connector.getNitrogenDioxide(timestamps.get(2)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testO3() { - double expectedValue = 55.08; - double actualValue = connector.getOzone(timestamps.get(3)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testO3() { + double expectedValue = 55.08; + double actualValue = connector.getOzone(timestamps.get(3)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testSO2() { - double expectedValue = 0.08; - double actualValue = connector.getSulfurDioxide(timestamps.get(60)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testSO2() { + double expectedValue = 0.08; + double actualValue = connector.getSulfurDioxide(timestamps.get(60)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testPM2_5() { - double expectedValue = 1.32; - double actualValue = connector.getFineParticulateMatter(timestamps.get(59)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testPM2_5() { + double expectedValue = 1.32; + double actualValue = connector.getFineParticulateMatter(timestamps.get(59)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testPM10() { - double expectedValue = 1.78; - double actualValue = connector.getCoarseParticulateMatter(timestamps.get(58)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testPM10() { + double expectedValue = 1.78; + double actualValue = connector.getCoarseParticulateMatter(timestamps.get(58)); + assertEquals(expectedValue, actualValue, 0.0001); + } - @Test - public void testNH3() { - double expectedValue = 1.85; - double actualValue = connector.getAmmonia(timestamps.get(57)); - assertEquals(expectedValue, actualValue, 0.0001); - } + @Test + public void testNH3() { + double expectedValue = 1.85; + double actualValue = connector.getAmmonia(timestamps.get(57)); + assertEquals(expectedValue, actualValue, 0.0001); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java index 63b1c5f..4dde1d9 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/AirPollution_WebsiteExampleTest.java @@ -10,92 +10,92 @@ import java.util.Date; import static org.junit.Assert.assertEquals; public class AirPollution_WebsiteExampleTest { - private OpenWeatherConnector connector; - - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("air_pollution"); - connector.retrieveData("website-example.json"); - } - - @Test - public void testLocation() { - double expectedLatitude = 50.0; - double expectedLongitude = 50.0; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } - - @Test - public void testDateTime() { + private OpenWeatherConnector connector; + + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("air_pollution"); + connector.retrieveData("website-example.json"); + } + + @Test + public void testLocation() { + double expectedLatitude = 50.0; + double expectedLongitude = 50.0; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } + + @Test + public void testDateTime() { // Date expectedValue = new Date(1605182400000L); - String expectedValue = "Thu Nov 12 06:00:00 CST 2020"; - Date actualValue = connector.getTimestamp(); - assertEquals(expectedValue, actualValue.toString()); - } - - @Test - public void testAirQualityIndex() { - OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.VERY_LOW; - OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(); - assertEquals(expectedValue, actualValue); - } - - @Test - public void testCO() { - double expectedValue = 201.94053649902344; - double actualValue = connector.getCarbonMonoxide(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testNO() { - double expectedValue = 0.01877197064459324; - double actualValue = connector.getNitrogenMonoxide(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testNO2() { - double expectedValue = 0.7711350917816162; - double actualValue = connector.getNitrogenDioxide(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testO3() { - double expectedValue = 68.66455078125; - double actualValue = connector.getOzone(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testSO2() { - double expectedValue = 0.6407499313354492; - double actualValue = connector.getSulfurDioxide(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testPM2_5() { - double expectedValue = 0.5; - double actualValue = connector.getFineParticulateMatter(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testPM10() { - double expectedValue = 0.540438711643219; - double actualValue = connector.getCoarseParticulateMatter(); - assertEquals(expectedValue, actualValue, 0.0001); - } - - @Test - public void testNH3() { - double expectedValue = 0.12369127571582794; - double actualValue = connector.getAmmonia(); - assertEquals(expectedValue, actualValue, 0.0001); - } + String expectedValue = "Thu Nov 12 06:00:00 CST 2020"; + Date actualValue = connector.getTimestamp(); + assertEquals(expectedValue, actualValue.toString()); + } + + @Test + public void testAirQualityIndex() { + OpenWeatherConnector.AirQuality expectedValue = OpenWeatherConnector.AirQuality.VERY_LOW; + OpenWeatherConnector.AirQuality actualValue = connector.getAirQualityIndex(); + assertEquals(expectedValue, actualValue); + } + + @Test + public void testCO() { + double expectedValue = 201.94053649902344; + double actualValue = connector.getCarbonMonoxide(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testNO() { + double expectedValue = 0.01877197064459324; + double actualValue = connector.getNitrogenMonoxide(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testNO2() { + double expectedValue = 0.7711350917816162; + double actualValue = connector.getNitrogenDioxide(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testO3() { + double expectedValue = 68.66455078125; + double actualValue = connector.getOzone(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testSO2() { + double expectedValue = 0.6407499313354492; + double actualValue = connector.getSulfurDioxide(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testPM2_5() { + double expectedValue = 0.5; + double actualValue = connector.getFineParticulateMatter(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testPM10() { + double expectedValue = 0.540438711643219; + double actualValue = connector.getCoarseParticulateMatter(); + assertEquals(expectedValue, actualValue, 0.0001); + } + + @Test + public void testNH3() { + double expectedValue = 0.12369127571582794; + double actualValue = connector.getAmmonia(); + assertEquals(expectedValue, actualValue, 0.0001); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java index 47195af..56dec5a 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/ExceptionsTest.java @@ -10,2416 +10,2416 @@ import java.util.Date; import static org.junit.Assert.*; public class ExceptionsTest { - OpenWeatherConnector weather, forecast, airPollution, airPollutionHistory, airPollutionForecast, oneCall, dataLess; + OpenWeatherConnector weather, forecast, airPollution, airPollutionHistory, airPollutionForecast, oneCall, dataLess; - @Before - public void setup() throws IOException { - weather = new OpenWeatherConnector("weather"); - weather.retrieveData("website-example.json"); - forecast = new OpenWeatherConnector("forecast"); - forecast.retrieveData("forecasted_weather-unl-nov7-nov12.json"); - airPollution = new OpenWeatherConnector("air_pollution"); - airPollution.retrieveData("website-example.json"); - airPollutionHistory = new OpenWeatherConnector("air_pollution/history"); - airPollutionHistory.retrieveData("air_pollution-unl-historical.json"); - airPollutionForecast = new OpenWeatherConnector("air_pollution/forecast"); - airPollutionForecast.retrieveData("stub.json"); - oneCall = new OpenWeatherConnector("onecall"); - oneCall.retrieveData("website-example.json"); - dataLess = new OpenWeatherConnector("weather"); - } + @Before + public void setup() throws IOException { + weather = new OpenWeatherConnector("weather"); + weather.retrieveData("website-example.json"); + forecast = new OpenWeatherConnector("forecast"); + forecast.retrieveData("forecasted_weather-unl-nov7-nov12.json"); + airPollution = new OpenWeatherConnector("air_pollution"); + airPollution.retrieveData("website-example.json"); + airPollutionHistory = new OpenWeatherConnector("air_pollution/history"); + airPollutionHistory.retrieveData("air_pollution-unl-historical.json"); + airPollutionForecast = new OpenWeatherConnector("air_pollution/forecast"); + airPollutionForecast.retrieveData("stub.json"); + oneCall = new OpenWeatherConnector("onecall"); + oneCall.retrieveData("website-example.json"); + dataLess = new OpenWeatherConnector("weather"); + } - @Test - public void testAllowedWeatherMethods() { - OpenWeatherConnector connector = weather; - connector.getLatitude(); - connector.getLongitude(); - connector.getTimestamp(); - connector.getTimestamps(); - connector.getTimestamps("Anything"); - connector.getWeatherCategories(); - connector.getWeatherDescriptions(); - connector.getVisibility(); - connector.getTemperature(); - connector.getHumidity(); - connector.getFeelsLike(); - connector.getPressure(); - connector.getWindDirection(); - connector.getWindGust(); - connector.getCloudCover(); - connector.getOneHourRainfall(); - connector.getThreeHourRainfall(); - connector.getOneHourSnowfall(); - connector.getThreeHourSnowfall(); - // pass - } + @Test + public void testAllowedWeatherMethods() { + OpenWeatherConnector connector = weather; + connector.getLatitude(); + connector.getLongitude(); + connector.getTimestamp(); + connector.getTimestamps(); + connector.getTimestamps("Anything"); + connector.getWeatherCategories(); + connector.getWeatherDescriptions(); + connector.getVisibility(); + connector.getTemperature(); + connector.getHumidity(); + connector.getFeelsLike(); + connector.getPressure(); + connector.getWindDirection(); + connector.getWindGust(); + connector.getCloudCover(); + connector.getOneHourRainfall(); + connector.getThreeHourRainfall(); + connector.getOneHourSnowfall(); + connector.getThreeHourSnowfall(); + // pass + } - @Test - public void testAllowedForecastMethods() { - OpenWeatherConnector connector = forecast; - Date timestamp = connector.getTimestamps().get(0); - connector.getLatitude(); - connector.getLongitude(); - connector.getTimestamp(); - connector.getTimestamps(); - connector.getTimestamps("Anything"); - connector.getWeatherCategories(timestamp); - connector.getWeatherDescriptions(timestamp); - connector.getVisibility(timestamp); - connector.getTemperature(timestamp); - connector.getHumidity(timestamp); - connector.getFeelsLike(timestamp); - connector.getPressure(timestamp); - connector.getWindDirection(timestamp); - connector.getWindGust(timestamp); - connector.getCloudCover(timestamp); - connector.getProbabilityOfPrecipitation(timestamp); - connector.getThreeHourRainfall(timestamp); - connector.getThreeHourSnowfall(timestamp); - // pass - } + @Test + public void testAllowedForecastMethods() { + OpenWeatherConnector connector = forecast; + Date timestamp = connector.getTimestamps().get(0); + connector.getLatitude(); + connector.getLongitude(); + connector.getTimestamp(); + connector.getTimestamps(); + connector.getTimestamps("Anything"); + connector.getWeatherCategories(timestamp); + connector.getWeatherDescriptions(timestamp); + connector.getVisibility(timestamp); + connector.getTemperature(timestamp); + connector.getHumidity(timestamp); + connector.getFeelsLike(timestamp); + connector.getPressure(timestamp); + connector.getWindDirection(timestamp); + connector.getWindGust(timestamp); + connector.getCloudCover(timestamp); + connector.getProbabilityOfPrecipitation(timestamp); + connector.getThreeHourRainfall(timestamp); + connector.getThreeHourSnowfall(timestamp); + // pass + } - @Test - public void testAllowedOneCallMethods() { - OpenWeatherConnector connector = oneCall; - Date minutely = connector.getTimestamps("minutely").get(0); - Date hourly = connector.getTimestamps("hourly").get(0); - Date daily = connector.getTimestamps("daily").get(0); - connector.getLatitude(); - connector.getLongitude(); - connector.getTimestamp(); - connector.getTimestamps(); - connector.getTimestamps("Anything"); - connector.getWeatherCategories(); - connector.getWeatherDescriptions(); - connector.getVisibility(); - connector.getTemperature(); - connector.getHumidity(); - connector.getFeelsLike(); - connector.getPressure(); - connector.getWindDirection(); - connector.getWindGust(); - connector.getCloudCover(); - connector.getOneHourRainfall(); - connector.getOneHourSnowfall(); - connector.getDewPoint(); - connector.getUltravioletIndex(); - connector.getMinutelyPrecipitation(minutely); // only - connector.getWeatherCategories(hourly); - connector.getWeatherDescriptions(daily); - connector.getVisibility(hourly); // only - connector.getTemperature(hourly); // only - connector.getHumidity(hourly); - connector.getFeelsLike(hourly); // only - connector.getPressure(daily); - connector.getWindDirection(hourly); - connector.getWindSpeed(daily); - connector.getWindGust(daily); - connector.getProbabilityOfPrecipitation(hourly); - connector.getCloudCover(daily); - connector.getDailyRainfall(daily); - connector.getDailySnowfall(daily); - connector.getOneHourRainfall(hourly); - connector.getOneHourSnowfall(hourly); - connector.getUltravioletIndex(daily); - connector.getDewPoint(hourly); - connector.getMorningTemperature(daily); - connector.getDaytimeTemperature(daily); - connector.getEveningTemperature(daily); - connector.getNighttimeTemperature(daily); - connector.getLowTemperature(daily); - connector.getHighTemperature(daily); - connector.getMorningFeelsLike(daily); - connector.getDaytimeFeelsLike(daily); - connector.getEveningFeelsLike(daily); - connector.getNighttimeFeelsLike(daily); - // pass - } + @Test + public void testAllowedOneCallMethods() { + OpenWeatherConnector connector = oneCall; + Date minutely = connector.getTimestamps("minutely").get(0); + Date hourly = connector.getTimestamps("hourly").get(0); + Date daily = connector.getTimestamps("daily").get(0); + connector.getLatitude(); + connector.getLongitude(); + connector.getTimestamp(); + connector.getTimestamps(); + connector.getTimestamps("Anything"); + connector.getWeatherCategories(); + connector.getWeatherDescriptions(); + connector.getVisibility(); + connector.getTemperature(); + connector.getHumidity(); + connector.getFeelsLike(); + connector.getPressure(); + connector.getWindDirection(); + connector.getWindGust(); + connector.getCloudCover(); + connector.getOneHourRainfall(); + connector.getOneHourSnowfall(); + connector.getDewPoint(); + connector.getUltravioletIndex(); + connector.getMinutelyPrecipitation(minutely); // only + connector.getWeatherCategories(hourly); + connector.getWeatherDescriptions(daily); + connector.getVisibility(hourly); // only + connector.getTemperature(hourly); // only + connector.getHumidity(hourly); + connector.getFeelsLike(hourly); // only + connector.getPressure(daily); + connector.getWindDirection(hourly); + connector.getWindSpeed(daily); + connector.getWindGust(daily); + connector.getProbabilityOfPrecipitation(hourly); + connector.getCloudCover(daily); + connector.getDailyRainfall(daily); + connector.getDailySnowfall(daily); + connector.getOneHourRainfall(hourly); + connector.getOneHourSnowfall(hourly); + connector.getUltravioletIndex(daily); + connector.getDewPoint(hourly); + connector.getMorningTemperature(daily); + connector.getDaytimeTemperature(daily); + connector.getEveningTemperature(daily); + connector.getNighttimeTemperature(daily); + connector.getLowTemperature(daily); + connector.getHighTemperature(daily); + connector.getMorningFeelsLike(daily); + connector.getDaytimeFeelsLike(daily); + connector.getEveningFeelsLike(daily); + connector.getNighttimeFeelsLike(daily); + // pass + } - @Test - public void testAllowedAirPollutionMethods() { - OpenWeatherConnector connector = airPollution; - Date timestamp = connector.getTimestamp(); - connector.getAirQualityIndex(); - connector.getCarbonMonoxide(); - connector.getNitrogenDioxide(); - connector.getOzone(); - connector.getSulfurDioxide(); - connector.getFineParticulateMatter(); - connector.getCoarseParticulateMatter(); - connector.getAmmonia(); - connector.getAirQualityIndex(timestamp); - connector.getCarbonMonoxide(timestamp); - connector.getNitrogenDioxide(timestamp); - connector.getOzone(timestamp); - connector.getSulfurDioxide(timestamp); - connector.getFineParticulateMatter(timestamp); - connector.getCoarseParticulateMatter(timestamp); - connector.getAmmonia(timestamp); - // pass - } + @Test + public void testAllowedAirPollutionMethods() { + OpenWeatherConnector connector = airPollution; + Date timestamp = connector.getTimestamp(); + connector.getAirQualityIndex(); + connector.getCarbonMonoxide(); + connector.getNitrogenDioxide(); + connector.getOzone(); + connector.getSulfurDioxide(); + connector.getFineParticulateMatter(); + connector.getCoarseParticulateMatter(); + connector.getAmmonia(); + connector.getAirQualityIndex(timestamp); + connector.getCarbonMonoxide(timestamp); + connector.getNitrogenDioxide(timestamp); + connector.getOzone(timestamp); + connector.getSulfurDioxide(timestamp); + connector.getFineParticulateMatter(timestamp); + connector.getCoarseParticulateMatter(timestamp); + connector.getAmmonia(timestamp); + // pass + } - @Test - public void testAllowedAirPollutionHistoryMethods() { - OpenWeatherConnector connector = airPollutionHistory; - Date timestamp = connector.getTimestamps().get(0); - connector.getAirQualityIndex(timestamp); - connector.getCarbonMonoxide(timestamp); - connector.getNitrogenDioxide(timestamp); - connector.getOzone(timestamp); - connector.getSulfurDioxide(timestamp); - connector.getFineParticulateMatter(timestamp); - connector.getCoarseParticulateMatter(timestamp); - connector.getAmmonia(timestamp); - // pass - } + @Test + public void testAllowedAirPollutionHistoryMethods() { + OpenWeatherConnector connector = airPollutionHistory; + Date timestamp = connector.getTimestamps().get(0); + connector.getAirQualityIndex(timestamp); + connector.getCarbonMonoxide(timestamp); + connector.getNitrogenDioxide(timestamp); + connector.getOzone(timestamp); + connector.getSulfurDioxide(timestamp); + connector.getFineParticulateMatter(timestamp); + connector.getCoarseParticulateMatter(timestamp); + connector.getAmmonia(timestamp); + // pass + } - @Test - public void testAllowedAirPollutionForecastMethods() { - OpenWeatherConnector connector = airPollutionForecast; - Date timestamp = connector.getTimestamps().get(0); - connector.getAirQualityIndex(timestamp); - connector.getCarbonMonoxide(timestamp); - connector.getNitrogenDioxide(timestamp); - connector.getOzone(timestamp); - connector.getSulfurDioxide(timestamp); - connector.getFineParticulateMatter(timestamp); - connector.getCoarseParticulateMatter(timestamp); - connector.getAmmonia(timestamp); - // pass - } + @Test + public void testAllowedAirPollutionForecastMethods() { + OpenWeatherConnector connector = airPollutionForecast; + Date timestamp = connector.getTimestamps().get(0); + connector.getAirQualityIndex(timestamp); + connector.getCarbonMonoxide(timestamp); + connector.getNitrogenDioxide(timestamp); + connector.getOzone(timestamp); + connector.getSulfurDioxide(timestamp); + connector.getFineParticulateMatter(timestamp); + connector.getCoarseParticulateMatter(timestamp); + connector.getAmmonia(timestamp); + // pass + } - @Test - public void testRetrieveDataNotCalled() { - OpenWeatherConnector connector = dataLess; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected IllegalStateException"; - try { - connector.getLatitude(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getLongitude(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getTimestamp(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getTimestamps(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getTimestamps("Anything"); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWeatherCategories(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWeatherDescriptions(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getVisibility(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getTemperature(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getHumidity(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getFeelsLike(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getPressure(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWindDirection(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWindGust(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCloudCover(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOneHourRainfall(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getThreeHourRainfall(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOneHourSnowfall(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getThreeHourSnowfall(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWeatherCategories(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWeatherDescriptions(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getHumidity(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getPressure(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWindDirection(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getWindGust(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCloudCover(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getProbabilityOfPrecipitation(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOzone(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getAirQualityIndex(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCarbonMonoxide(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getNitrogenDioxide(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOzone(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getSulfurDioxide(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getFineParticulateMatter(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getCoarseParticulateMatter(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getAmmonia(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (IllegalStateException ignored) { - } - // pass - } + @Test + public void testRetrieveDataNotCalled() { + OpenWeatherConnector connector = dataLess; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected IllegalStateException"; + try { + connector.getLatitude(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getLongitude(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getTimestamp(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getTimestamps(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getTimestamps("Anything"); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWeatherCategories(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWeatherDescriptions(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getVisibility(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getTemperature(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getHumidity(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getFeelsLike(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getPressure(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWindDirection(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWindGust(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCloudCover(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOneHourRainfall(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getThreeHourRainfall(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOneHourSnowfall(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getThreeHourSnowfall(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWeatherCategories(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWeatherDescriptions(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getHumidity(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getPressure(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWindDirection(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getWindGust(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCloudCover(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getProbabilityOfPrecipitation(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOzone(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getAirQualityIndex(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCarbonMonoxide(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getNitrogenDioxide(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOzone(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getSulfurDioxide(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getFineParticulateMatter(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getCoarseParticulateMatter(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getAmmonia(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (IllegalStateException ignored) { + } + // pass + } - @Test - public void testProhibitedWeatherMethods() { - OpenWeatherConnector connector = weather; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getWeatherCategories(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getProbabilityOfPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedWeatherMethods() { + OpenWeatherConnector connector = weather; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getWeatherCategories(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getProbabilityOfPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testProhibitedForecastMethods() { - OpenWeatherConnector connector = forecast; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getWeatherCategories(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedForecastMethods() { + OpenWeatherConnector connector = forecast; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getWeatherCategories(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testProhibitedOneCallMethods() { - OpenWeatherConnector connector = oneCall; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedOneCallMethods() { + OpenWeatherConnector connector = oneCall; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testProhibitedAirPollutionMethods() { - OpenWeatherConnector connector = airPollution; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getWeatherCategories(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherCategories(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getProbabilityOfPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedAirPollutionMethods() { + OpenWeatherConnector connector = airPollution; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getWeatherCategories(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherCategories(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getProbabilityOfPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testProhibitedAirPollutionHistoryMethods() { - OpenWeatherConnector connector = airPollutionHistory; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getWeatherCategories(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherCategories(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getProbabilityOfPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedAirPollutionHistoryMethods() { + OpenWeatherConnector connector = airPollutionHistory; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getWeatherCategories(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherCategories(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getProbabilityOfPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testProhibitedAirPollutionForecastMethods() { - OpenWeatherConnector connector = airPollutionForecast; - Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getWeatherCategories(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherCategories(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWeatherDescriptions(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHumidity(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getPressure(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindDirection(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getWindGust(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCloudCover(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getProbabilityOfPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getThreeHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAirQualityIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCarbonMonoxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNitrogenDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOzone(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getSulfurDioxide(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getFineParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getCoarseParticulateMatter(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getAmmonia(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailyRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDailySnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDewPoint(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getUltravioletIndex(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); - } - // pass - } + @Test + public void testProhibitedAirPollutionForecastMethods() { + OpenWeatherConnector connector = airPollutionForecast; + Date timestamp = OpenWeatherConnector.IMPOSSIBLE_DATE; + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getWeatherCategories(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherCategories(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWeatherDescriptions(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHumidity(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getPressure(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindDirection(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getWindGust(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCloudCover(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getProbabilityOfPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getThreeHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAirQualityIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCarbonMonoxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNitrogenDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOzone(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getSulfurDioxide(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getFineParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getCoarseParticulateMatter(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getAmmonia(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailyRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDailySnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDewPoint(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getUltravioletIndex(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertTrue(exception.getMessage().startsWith("Attempted to call method on an inapplicable dataset")); + } + // pass + } - @Test - public void testOnlyMinutelyMethods() { - OpenWeatherConnector connector = oneCall; - Date timestamp = connector.getTimestamps("minutely").get(0); - String failMessage = "Expected UnsupportedOperationException"; - connector.getMinutelyPrecipitation(timestamp); - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - } + @Test + public void testOnlyMinutelyMethods() { + OpenWeatherConnector connector = oneCall; + Date timestamp = connector.getTimestamps("minutely").get(0); + String failMessage = "Expected UnsupportedOperationException"; + connector.getMinutelyPrecipitation(timestamp); + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + } - @Test - public void testOnlyHourlyMethods() { - OpenWeatherConnector connector = oneCall; - Date timestamp = connector.getTimestamps("hourly").get(0); - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage()); - } - connector.getVisibility(timestamp); - connector.getTemperature(timestamp); - connector.getFeelsLike(timestamp); - connector.getOneHourRainfall(timestamp); - connector.getOneHourSnowfall(timestamp); - try { - connector.getMorningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getDaytimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getEveningTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getNighttimeTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getLowTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getHighTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getMorningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getDaytimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getEveningFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - try { - connector.getNighttimeFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); - } - } + @Test + public void testOnlyHourlyMethods() { + OpenWeatherConnector connector = oneCall; + Date timestamp = connector.getTimestamps("hourly").get(0); + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage()); + } + connector.getVisibility(timestamp); + connector.getTemperature(timestamp); + connector.getFeelsLike(timestamp); + connector.getOneHourRainfall(timestamp); + connector.getOneHourSnowfall(timestamp); + try { + connector.getMorningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getDaytimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getEveningTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getNighttimeTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getLowTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getHighTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getMorningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getDaytimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getEveningFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + try { + connector.getNighttimeFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for daily timestamps.", exception.getMessage()); + } + } - @Test - public void testOnlyDailyMethods() { - OpenWeatherConnector connector = oneCall; - Date timestamp = connector.getTimestamps("daily").get(0); - String failMessage = "Expected UnsupportedOperationException"; - try { - connector.getMinutelyPrecipitation(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage()); - } - try { - connector.getVisibility(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getTemperature(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getFeelsLike(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getOneHourRainfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - try { - connector.getOneHourSnowfall(timestamp); - fail(failMessage); - } catch (UnsupportedOperationException exception) { - assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); - } - connector.getMorningTemperature(timestamp); - connector.getDaytimeTemperature(timestamp); - connector.getEveningTemperature(timestamp); - connector.getNighttimeTemperature(timestamp); - connector.getLowTemperature(timestamp); - connector.getHighTemperature(timestamp); - connector.getMorningFeelsLike(timestamp); - connector.getDaytimeFeelsLike(timestamp); - connector.getEveningFeelsLike(timestamp); - connector.getNighttimeFeelsLike(timestamp); - } + @Test + public void testOnlyDailyMethods() { + OpenWeatherConnector connector = oneCall; + Date timestamp = connector.getTimestamps("daily").get(0); + String failMessage = "Expected UnsupportedOperationException"; + try { + connector.getMinutelyPrecipitation(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for minutely timestamps.", exception.getMessage()); + } + try { + connector.getVisibility(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getTemperature(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getFeelsLike(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getOneHourRainfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + try { + connector.getOneHourSnowfall(timestamp); + fail(failMessage); + } catch (UnsupportedOperationException exception) { + assertEquals("This onecall datum is only available for hourly timestamps.", exception.getMessage()); + } + connector.getMorningTemperature(timestamp); + connector.getDaytimeTemperature(timestamp); + connector.getEveningTemperature(timestamp); + connector.getNighttimeTemperature(timestamp); + connector.getLowTemperature(timestamp); + connector.getHighTemperature(timestamp); + connector.getMorningFeelsLike(timestamp); + connector.getDaytimeFeelsLike(timestamp); + connector.getEveningFeelsLike(timestamp); + connector.getNighttimeFeelsLike(timestamp); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java index b62c3c2..7770b84 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/Forecast_UnlNov7ToNov12Test.java @@ -11,115 +11,114 @@ import java.util.List; import static org.junit.Assert.assertEquals; public class Forecast_UnlNov7ToNov12Test { - private OpenWeatherConnector connector; - private Date Sunday, Monday, Tuesday, Wednesday, Thursday, Friday; + private OpenWeatherConnector connector; + private Date Sunday, Monday, Tuesday, Wednesday, Thursday, Friday; - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("forecast"); - connector.retrieveData("forecasted_weather-unl-nov7-nov12.json"); - List<Date> timestamps = connector.getTimestamps(); - Sunday = timestamps.get(0); - Monday = timestamps.get(8); - Tuesday = timestamps.get(16); - Wednesday = timestamps.get(24); - Thursday = timestamps.get(32); - Friday = timestamps.get(39); - } + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("forecast"); + connector.retrieveData("forecasted_weather-unl-nov7-nov12.json"); + List<Date> timestamps = connector.getTimestamps(); + Sunday = timestamps.get(0); + Monday = timestamps.get(8); + Tuesday = timestamps.get(16); + Wednesday = timestamps.get(24); + Thursday = timestamps.get(32); + Friday = timestamps.get(39); + } - @Test - public void testLocation() { - double expectedLatitude = 40.8206; - double expectedLongitude = -96.6928; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } + @Test + public void testLocation() { + double expectedLatitude = 40.8206; + double expectedLongitude = -96.6928; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } - @Test - public void testWeather() { - Date timestamp = Sunday; - List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of( - OpenWeatherConnector.WeatherCategory.CLEAR - ); - List<String> expectedDescriptions = List.of("clear sky"); - int expectedListSize = 1; - List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(timestamp); - List<String> actualDescriptions = connector.getWeatherDescriptions(timestamp); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategories, actualCategories); - assertEquals(expectedDescriptions, actualDescriptions); - } + @Test + public void testWeather() { + Date timestamp = Sunday; + List<OpenWeatherConnector.WeatherCategory> expectedCategories = List + .of(OpenWeatherConnector.WeatherCategory.CLEAR); + List<String> expectedDescriptions = List.of("clear sky"); + int expectedListSize = 1; + List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(timestamp); + List<String> actualDescriptions = connector.getWeatherDescriptions(timestamp); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategories, actualCategories); + assertEquals(expectedDescriptions, actualDescriptions); + } - @Test - public void testMainObservations() { - Date timestamp = Monday; - long expectedVisibility = 10000; - double expectedAmbientTemperature = 285.91; - long expectedHumidity = 70; - double expectedFeelsLikeTemperature = 285.07; - long expectedPressure = 1016; - long actualVisibility = connector.getVisibility(timestamp); - double actualAmbientTemperature = connector.getTemperature(timestamp); - long actualHumidity = connector.getHumidity(timestamp); - double actualFeelsLikeTemperature = connector.getFeelsLike(timestamp); - long actualPressure = connector.getPressure(timestamp); - assertEquals(expectedVisibility, actualVisibility); - assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); - assertEquals(expectedPressure, actualPressure); - } + @Test + public void testMainObservations() { + Date timestamp = Monday; + long expectedVisibility = 10000; + double expectedAmbientTemperature = 285.91; + long expectedHumidity = 70; + double expectedFeelsLikeTemperature = 285.07; + long expectedPressure = 1016; + long actualVisibility = connector.getVisibility(timestamp); + double actualAmbientTemperature = connector.getTemperature(timestamp); + long actualHumidity = connector.getHumidity(timestamp); + double actualFeelsLikeTemperature = connector.getFeelsLike(timestamp); + long actualPressure = connector.getPressure(timestamp); + assertEquals(expectedVisibility, actualVisibility); + assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); + assertEquals(expectedPressure, actualPressure); + } - @Test - public void testWinds() { - Date timestamp = Tuesday; - long expectedDirection = 357; - double expectedSpeed = 5.6; - double expectedGust = 9.73; - long actualDirection = connector.getWindDirection(timestamp); - double actualSpeed = connector.getWindSpeed(timestamp); - double actualGust = connector.getWindGust(timestamp); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); - } + @Test + public void testWinds() { + Date timestamp = Tuesday; + long expectedDirection = 357; + double expectedSpeed = 5.6; + double expectedGust = 9.73; + long actualDirection = connector.getWindDirection(timestamp); + double actualSpeed = connector.getWindSpeed(timestamp); + double actualGust = connector.getWindGust(timestamp); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); + } - @Test - public void testClouds() { - Date timestamp = Friday; - long expectedValue = 48; - long actualValue = connector.getCloudCover(timestamp); - assertEquals(expectedValue, actualValue); - } + @Test + public void testClouds() { + Date timestamp = Friday; + long expectedValue = 48; + long actualValue = connector.getCloudCover(timestamp); + assertEquals(expectedValue, actualValue); + } - @Test - public void testPrecipitationWhenNoRain() { - Date timestamp = Thursday; - double expectedProbability = 0.0; - double expected3HourRain = 0.0; - double expected3HourSnow = 0.0; - double actualProbability = connector.getProbabilityOfPrecipitation(timestamp); - double actual3HourRain = connector.getThreeHourRainfall(timestamp); - double actual3HourSnow = connector.getThreeHourSnowfall(timestamp); - assertEquals(expectedProbability, actualProbability, 0.0001); - assertEquals(expected3HourRain, actual3HourRain, 0.0001); - assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); - } + @Test + public void testPrecipitationWhenNoRain() { + Date timestamp = Thursday; + double expectedProbability = 0.0; + double expected3HourRain = 0.0; + double expected3HourSnow = 0.0; + double actualProbability = connector.getProbabilityOfPrecipitation(timestamp); + double actual3HourRain = connector.getThreeHourRainfall(timestamp); + double actual3HourSnow = connector.getThreeHourSnowfall(timestamp); + assertEquals(expectedProbability, actualProbability, 0.0001); + assertEquals(expected3HourRain, actual3HourRain, 0.0001); + assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); + } - @Test - public void testPrecipitationWhenRainForecasted() { - Date timestamp = Wednesday; - double expectedProbability = 0.27; - double expected3HourRain = 0.18; - double expected3HourSnow = 0.0; - double actualProbability = connector.getProbabilityOfPrecipitation(timestamp); - double actual3HourRain = connector.getThreeHourRainfall(timestamp); - double actual3HourSnow = connector.getThreeHourSnowfall(timestamp); - assertEquals(expectedProbability, actualProbability, 0.0001); - assertEquals(expected3HourRain, actual3HourRain, 0.0001); - assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); - } + @Test + public void testPrecipitationWhenRainForecasted() { + Date timestamp = Wednesday; + double expectedProbability = 0.27; + double expected3HourRain = 0.18; + double expected3HourSnow = 0.0; + double actualProbability = connector.getProbabilityOfPrecipitation(timestamp); + double actual3HourRain = connector.getThreeHourRainfall(timestamp); + double actual3HourSnow = connector.getThreeHourSnowfall(timestamp); + assertEquals(expectedProbability, actualProbability, 0.0001); + assertEquals(expected3HourRain, actual3HourRain, 0.0001); + assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java index 81883c2..039f857 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/OneCall_WebsiteExampleTest.java @@ -12,278 +12,277 @@ import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; public class OneCall_WebsiteExampleTest { - private OpenWeatherConnector connector; - private Date minutely, hourly, daily; + private OpenWeatherConnector connector; + private Date minutely, hourly, daily; - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("onecall"); - connector.retrieveData("website-example.json"); - minutely = connector.getTimestamps("minutely").get(0); - hourly = connector.getTimestamps("hourly").get(0); - daily = connector.getTimestamps("daily").get(0); - } + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("onecall"); + connector.retrieveData("website-example.json"); + minutely = connector.getTimestamps("minutely").get(0); + hourly = connector.getTimestamps("hourly").get(0); + daily = connector.getTimestamps("daily").get(0); + } - @Test - public void testLocation() { - double expectedLatitude = 33.44; - double expectedLongitude = -94.04; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } + @Test + public void testLocation() { + double expectedLatitude = 33.44; + double expectedLongitude = -94.04; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } - @Test - public void testCurrentDateTime() { + @Test + public void testCurrentDateTime() { // Date expectedValue = new Date(16183170400000L); - String expectedValue = "Tue Apr 13 07:30:40 CDT 2021"; - Date actualValue = connector.getTimestamp(); - assertEquals(expectedValue, actualValue.toString()); - } + String expectedValue = "Tue Apr 13 07:30:40 CDT 2021"; + Date actualValue = connector.getTimestamp(); + assertEquals(expectedValue, actualValue.toString()); + } - @Test - public void testListDateTimes() { + @Test + public void testListDateTimes() { // List<Date> expectedMinutes = List.of(new Date(1618317060000L)); // List<Date> expectedHours = List.of(new Date(1618315200000L)); // List<Date> expectedDays = List.of(new Date(1618308000000L)); - List<String> expectedMinutes = List.of("Tue Apr 13 07:31:00 CDT 2021"); - List<String> expectedHours = List.of("Tue Apr 13 07:00:00 CDT 2021"); - List<String> expectedDays = List.of("Tue Apr 13 05:00:00 CDT 2021"); - List<String> actualMinutes = connector.getTimestamps("minutely") - .stream().map(Date::toString).collect(Collectors.toList()); - List<String> actualHours = connector.getTimestamps("hourly") - .stream().map(Date::toString).collect(Collectors.toList()); - List<String> actualDays = connector.getTimestamps("daily") - .stream().map(Date::toString).collect(Collectors.toList()); - assertEquals(expectedMinutes, actualMinutes); - assertEquals(expectedHours, actualHours); - assertEquals(expectedDays, actualDays); - } + List<String> expectedMinutes = List.of("Tue Apr 13 07:31:00 CDT 2021"); + List<String> expectedHours = List.of("Tue Apr 13 07:00:00 CDT 2021"); + List<String> expectedDays = List.of("Tue Apr 13 05:00:00 CDT 2021"); + List<String> actualMinutes = connector.getTimestamps("minutely").stream().map(Date::toString) + .collect(Collectors.toList()); + List<String> actualHours = connector.getTimestamps("hourly").stream().map(Date::toString) + .collect(Collectors.toList()); + List<String> actualDays = connector.getTimestamps("daily").stream().map(Date::toString) + .collect(Collectors.toList()); + assertEquals(expectedMinutes, actualMinutes); + assertEquals(expectedHours, actualHours); + assertEquals(expectedDays, actualDays); + } - @Test - public void testWeather() { - OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.RAIN; - String expectedDescription = "light rain"; - int expectedListSize = 1; - List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); - List<String> actualDescriptions = connector.getWeatherDescriptions(); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategory, actualCategories.get(0)); - assertEquals(expectedDescription, actualDescriptions.get(0)); - } + @Test + public void testWeather() { + OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.RAIN; + String expectedDescription = "light rain"; + int expectedListSize = 1; + List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); + List<String> actualDescriptions = connector.getWeatherDescriptions(); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategory, actualCategories.get(0)); + assertEquals(expectedDescription, actualDescriptions.get(0)); + } - @Test - public void testMainObservationsCommonWithWeatherDataset() { - long expectedVisibility = 10000; - double expectedAmbientTemperature = 284.07; - long expectedHumidity = 62; - double expectedFeelsLikeTemperature = 282.84; - long expectedPressure = 1019; - long actualVisibility = connector.getVisibility(); - double actualAmbientTemperature = connector.getTemperature(); - long actualHumidity = connector.getHumidity(); - double actualFeelsLikeTemperature = connector.getFeelsLike(); - long actualPressure = connector.getPressure(); - assertEquals(expectedVisibility, actualVisibility); - assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); - assertEquals(expectedPressure, actualPressure); - } + @Test + public void testMainObservationsCommonWithWeatherDataset() { + long expectedVisibility = 10000; + double expectedAmbientTemperature = 284.07; + long expectedHumidity = 62; + double expectedFeelsLikeTemperature = 282.84; + long expectedPressure = 1019; + long actualVisibility = connector.getVisibility(); + double actualAmbientTemperature = connector.getTemperature(); + long actualHumidity = connector.getHumidity(); + double actualFeelsLikeTemperature = connector.getFeelsLike(); + long actualPressure = connector.getPressure(); + assertEquals(expectedVisibility, actualVisibility); + assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); + assertEquals(expectedPressure, actualPressure); + } - @Test - public void testMainObservationsUniqueToOnecallDataset() { - double expectedDewPoint = 277.08; - double expectedUVI = 0.89; - double actualDewPoint = connector.getDewPoint(); - double actualUVI = connector.getUltravioletIndex(); - assertEquals(expectedDewPoint, actualDewPoint, 0.0001); - assertEquals(expectedUVI, actualUVI, 0.0001); - } + @Test + public void testMainObservationsUniqueToOnecallDataset() { + double expectedDewPoint = 277.08; + double expectedUVI = 0.89; + double actualDewPoint = connector.getDewPoint(); + double actualUVI = connector.getUltravioletIndex(); + assertEquals(expectedDewPoint, actualDewPoint, 0.0001); + assertEquals(expectedUVI, actualUVI, 0.0001); + } - @Test - public void testWinds() { - long expectedDirection = 300; - double expectedSpeed = 6.0; - double expectedGust = 6.0; - long actualDirection = connector.getWindDirection(); - double actualSpeed = connector.getWindSpeed(); - double actualGust = connector.getWindGust(); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); - } + @Test + public void testWinds() { + long expectedDirection = 300; + double expectedSpeed = 6.0; + double expectedGust = 6.0; + long actualDirection = connector.getWindDirection(); + double actualSpeed = connector.getWindSpeed(); + double actualGust = connector.getWindGust(); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); + } - @Test - public void testClouds() { - long expectedValue = 0; - long actualValue = connector.getCloudCover(); - assertEquals(expectedValue, actualValue); - } + @Test + public void testClouds() { + long expectedValue = 0; + long actualValue = connector.getCloudCover(); + assertEquals(expectedValue, actualValue); + } - @Test - public void testPrecipitation() { - double expected1HourRain = 0.21; - double expected1HourSnow = 0.0; - double actual1HourRain = connector.getOneHourRainfall(); - double actual1HourSnow = connector.getOneHourSnowfall(); - assertEquals(expected1HourRain, actual1HourRain, 0.0001); - assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); - } + @Test + public void testPrecipitation() { + double expected1HourRain = 0.21; + double expected1HourSnow = 0.0; + double actual1HourRain = connector.getOneHourRainfall(); + double actual1HourSnow = connector.getOneHourSnowfall(); + assertEquals(expected1HourRain, actual1HourRain, 0.0001); + assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); + } - @Test - public void testWeatherForecast() { - List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of( - OpenWeatherConnector.WeatherCategory.CLOUDS - ); - List<String> expectedDescriptions = List.of("few clouds"); - int expectedListSize = 1; - List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(hourly); - List<String> actualDescriptions = connector.getWeatherDescriptions(hourly); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategories, actualCategories); - assertEquals(expectedDescriptions, actualDescriptions); + @Test + public void testWeatherForecast() { + List<OpenWeatherConnector.WeatherCategory> expectedCategories = List + .of(OpenWeatherConnector.WeatherCategory.CLOUDS); + List<String> expectedDescriptions = List.of("few clouds"); + int expectedListSize = 1; + List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(hourly); + List<String> actualDescriptions = connector.getWeatherDescriptions(hourly); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategories, actualCategories); + assertEquals(expectedDescriptions, actualDescriptions); - expectedCategories = List.of(OpenWeatherConnector.WeatherCategory.RAIN); - expectedDescriptions = List.of("light rain"); - actualCategories = connector.getWeatherCategories(daily); - actualDescriptions = connector.getWeatherDescriptions(daily); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategories, actualCategories); - assertEquals(expectedDescriptions, actualDescriptions); - } + expectedCategories = List.of(OpenWeatherConnector.WeatherCategory.RAIN); + expectedDescriptions = List.of("light rain"); + actualCategories = connector.getWeatherCategories(daily); + actualDescriptions = connector.getWeatherDescriptions(daily); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategories, actualCategories); + assertEquals(expectedDescriptions, actualDescriptions); + } - @Test - public void testMainObservationForecast() { - long expectedVisibility = 306; - double expectedAmbientTemperature = 282.58; - long expectedHumidity = 68; - double expectedFeelsLikeTemperature = 280.4; - long expectedPressure = 1019; - double expectedDewPoint = 276.98; - double expectedUVI = 1.4; - long actualVisibility = connector.getVisibility(hourly); - double actualAmbientTemperature = connector.getTemperature(hourly); - long actualHumidity = connector.getHumidity(hourly); - double actualFeelsLikeTemperature = connector.getFeelsLike(hourly); - long actualPressure = connector.getPressure(hourly); - double actualDewPoint = connector.getDewPoint(hourly); - double actualUVI = connector.getUltravioletIndex(hourly); - assertEquals(expectedVisibility, actualVisibility); - assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); - assertEquals(expectedPressure, actualPressure); - assertEquals(expectedDewPoint, actualDewPoint, 0.0001); - assertEquals(expectedUVI, actualUVI, 0.0001); + @Test + public void testMainObservationForecast() { + long expectedVisibility = 306; + double expectedAmbientTemperature = 282.58; + long expectedHumidity = 68; + double expectedFeelsLikeTemperature = 280.4; + long expectedPressure = 1019; + double expectedDewPoint = 276.98; + double expectedUVI = 1.4; + long actualVisibility = connector.getVisibility(hourly); + double actualAmbientTemperature = connector.getTemperature(hourly); + long actualHumidity = connector.getHumidity(hourly); + double actualFeelsLikeTemperature = connector.getFeelsLike(hourly); + long actualPressure = connector.getPressure(hourly); + double actualDewPoint = connector.getDewPoint(hourly); + double actualUVI = connector.getUltravioletIndex(hourly); + assertEquals(expectedVisibility, actualVisibility); + assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); + assertEquals(expectedPressure, actualPressure); + assertEquals(expectedDewPoint, actualDewPoint, 0.0001); + assertEquals(expectedUVI, actualUVI, 0.0001); - expectedHumidity = 81; - expectedPressure = 1020; - expectedDewPoint = 276.77; - expectedUVI = 1.93; - actualHumidity = connector.getHumidity(daily); - actualPressure = connector.getPressure(daily); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedPressure, actualPressure); - actualDewPoint = connector.getDewPoint(daily); - actualUVI = connector.getUltravioletIndex(daily); - assertEquals(expectedDewPoint, actualDewPoint, 0.0001); - assertEquals(expectedUVI, actualUVI, 0.0001); + expectedHumidity = 81; + expectedPressure = 1020; + expectedDewPoint = 276.77; + expectedUVI = 1.93; + actualHumidity = connector.getHumidity(daily); + actualPressure = connector.getPressure(daily); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedPressure, actualPressure); + actualDewPoint = connector.getDewPoint(daily); + actualUVI = connector.getUltravioletIndex(daily); + assertEquals(expectedDewPoint, actualDewPoint, 0.0001); + assertEquals(expectedUVI, actualUVI, 0.0001); - double expectedMorningTemperature = 278.49; - double expectedDaytimeTemperature = 279.79; - double expectedEveningTemperature = 279.21; - double expectedNighttimeTemperature = 275.09; - double expectedHighTemperature = 284.07; - double expectedLowTemperature = 275.09; - double expectedMorningFeelsLikeTemperature = 276.27; - double expectedDaytimeFeelsLikeTemperature = 277.59; - double expectedEveningFeelsLikeTemperature = 276.49; - double expectedNighttimeFeelsLikeTemperature = 276.27; - double actualMorningTemperature = connector.getMorningTemperature(daily); - double actualDaytimeTemperature = connector.getDaytimeTemperature(daily); - double actualEveningTemperature = connector.getEveningTemperature(daily); - double actualNighttimeTemperature = connector.getNighttimeTemperature(daily); - double actualHighTemperature = connector.getHighTemperature(daily); - double actualLowTemperature = connector.getLowTemperature(daily); - double actualMorningFeelsLikeTemperature = connector.getMorningFeelsLike(daily); - double actualDaytimeFeelsLikeTemperature = connector.getDaytimeFeelsLike(daily); - double actualEveningFeelsLikeTemperature = connector.getEveningFeelsLike(daily); - double actualNighttimeFeelsLikeTemperature = connector.getNighttimeFeelsLike(daily); - assertEquals(expectedMorningTemperature, actualMorningTemperature, 0.0001); - assertEquals(expectedDaytimeTemperature, actualDaytimeTemperature, 0.0001); - assertEquals(expectedEveningTemperature, actualEveningTemperature, 0.0001); - assertEquals(expectedNighttimeTemperature, actualNighttimeTemperature, 0.0001); - assertEquals(expectedLowTemperature, actualLowTemperature, 0.0001); - assertEquals(expectedHighTemperature, actualHighTemperature, 0.0001); - assertEquals(expectedMorningFeelsLikeTemperature, actualMorningFeelsLikeTemperature, 0.0001); - assertEquals(expectedDaytimeFeelsLikeTemperature, actualDaytimeFeelsLikeTemperature, 0.0001); - assertEquals(expectedEveningFeelsLikeTemperature, actualEveningFeelsLikeTemperature, 0.0001); - assertEquals(expectedNighttimeFeelsLikeTemperature, actualNighttimeFeelsLikeTemperature, 0.0001); - } + double expectedMorningTemperature = 278.49; + double expectedDaytimeTemperature = 279.79; + double expectedEveningTemperature = 279.21; + double expectedNighttimeTemperature = 275.09; + double expectedHighTemperature = 284.07; + double expectedLowTemperature = 275.09; + double expectedMorningFeelsLikeTemperature = 276.27; + double expectedDaytimeFeelsLikeTemperature = 277.59; + double expectedEveningFeelsLikeTemperature = 276.49; + double expectedNighttimeFeelsLikeTemperature = 276.27; + double actualMorningTemperature = connector.getMorningTemperature(daily); + double actualDaytimeTemperature = connector.getDaytimeTemperature(daily); + double actualEveningTemperature = connector.getEveningTemperature(daily); + double actualNighttimeTemperature = connector.getNighttimeTemperature(daily); + double actualHighTemperature = connector.getHighTemperature(daily); + double actualLowTemperature = connector.getLowTemperature(daily); + double actualMorningFeelsLikeTemperature = connector.getMorningFeelsLike(daily); + double actualDaytimeFeelsLikeTemperature = connector.getDaytimeFeelsLike(daily); + double actualEveningFeelsLikeTemperature = connector.getEveningFeelsLike(daily); + double actualNighttimeFeelsLikeTemperature = connector.getNighttimeFeelsLike(daily); + assertEquals(expectedMorningTemperature, actualMorningTemperature, 0.0001); + assertEquals(expectedDaytimeTemperature, actualDaytimeTemperature, 0.0001); + assertEquals(expectedEveningTemperature, actualEveningTemperature, 0.0001); + assertEquals(expectedNighttimeTemperature, actualNighttimeTemperature, 0.0001); + assertEquals(expectedLowTemperature, actualLowTemperature, 0.0001); + assertEquals(expectedHighTemperature, actualHighTemperature, 0.0001); + assertEquals(expectedMorningFeelsLikeTemperature, actualMorningFeelsLikeTemperature, 0.0001); + assertEquals(expectedDaytimeFeelsLikeTemperature, actualDaytimeFeelsLikeTemperature, 0.0001); + assertEquals(expectedEveningFeelsLikeTemperature, actualEveningFeelsLikeTemperature, 0.0001); + assertEquals(expectedNighttimeFeelsLikeTemperature, actualNighttimeFeelsLikeTemperature, 0.0001); + } - @Test - public void testWindForecast() { - long expectedDirection = 296; - double expectedSpeed = 4.12; - double expectedGust = 7.33; - long actualDirection = connector.getWindDirection(hourly); - double actualSpeed = connector.getWindSpeed(hourly); - double actualGust = connector.getWindGust(hourly); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); + @Test + public void testWindForecast() { + long expectedDirection = 296; + double expectedSpeed = 4.12; + double expectedGust = 7.33; + long actualDirection = connector.getWindDirection(hourly); + double actualSpeed = connector.getWindSpeed(hourly); + double actualGust = connector.getWindGust(hourly); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); - expectedDirection = 294; - expectedSpeed = 3.06; - expectedGust = 3.06; - actualDirection = connector.getWindDirection(daily); - actualSpeed = connector.getWindSpeed(daily); - actualGust = connector.getWindGust(daily); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); - } + expectedDirection = 294; + expectedSpeed = 3.06; + expectedGust = 3.06; + actualDirection = connector.getWindDirection(daily); + actualSpeed = connector.getWindSpeed(daily); + actualGust = connector.getWindGust(daily); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); + } - @Test - public void testCloudinessForecast() { - long expectedClouds = 19; - long actualClouds = connector.getCloudCover(hourly); - assertEquals(expectedClouds, actualClouds); + @Test + public void testCloudinessForecast() { + long expectedClouds = 19; + long actualClouds = connector.getCloudCover(hourly); + assertEquals(expectedClouds, actualClouds); - expectedClouds = 56; - actualClouds = connector.getCloudCover(daily); - assertEquals(expectedClouds, actualClouds); - } + expectedClouds = 56; + actualClouds = connector.getCloudCover(daily); + assertEquals(expectedClouds, actualClouds); + } - @Test - public void testPrecipitationForecast() { - double expectedPrecipitation = 0.205; - double actualPrecipitation = connector.getMinutelyPrecipitation(minutely); - assertEquals(expectedPrecipitation, actualPrecipitation, 0.0001); + @Test + public void testPrecipitationForecast() { + double expectedPrecipitation = 0.205; + double actualPrecipitation = connector.getMinutelyPrecipitation(minutely); + assertEquals(expectedPrecipitation, actualPrecipitation, 0.0001); - double expectedProbability = 0.0; - double expectedRain = 0.0; - double expectedSnow = 0.0; - double actualProbability = connector.getProbabilityOfPrecipitation(hourly); - double actualRain = connector.getOneHourRainfall(hourly); - double actualSnow = connector.getOneHourSnowfall(hourly); - assertEquals(expectedProbability, actualProbability, 0.0001); - assertEquals(expectedRain, actualRain, 0.0001); - assertEquals(expectedSnow, actualSnow, 0.0001); + double expectedProbability = 0.0; + double expectedRain = 0.0; + double expectedSnow = 0.0; + double actualProbability = connector.getProbabilityOfPrecipitation(hourly); + double actualRain = connector.getOneHourRainfall(hourly); + double actualSnow = connector.getOneHourSnowfall(hourly); + assertEquals(expectedProbability, actualProbability, 0.0001); + assertEquals(expectedRain, actualRain, 0.0001); + assertEquals(expectedSnow, actualSnow, 0.0001); - expectedProbability = 0.2; - expectedRain = 0.62; - expectedSnow = 0.0; - actualProbability = connector.getProbabilityOfPrecipitation(daily); - actualRain = connector.getDailyRainfall(daily); - actualSnow = connector.getDailySnowfall(daily); - assertEquals(expectedProbability, actualProbability, 0.0001); - assertEquals(expectedRain, actualRain, 0.0001); - assertEquals(expectedSnow, actualSnow, 0.0001); - } + expectedProbability = 0.2; + expectedRain = 0.62; + expectedSnow = 0.0; + actualProbability = connector.getProbabilityOfPrecipitation(daily); + actualRain = connector.getDailyRainfall(daily); + actualSnow = connector.getDailySnowfall(daily); + assertEquals(expectedProbability, actualProbability, 0.0001); + assertEquals(expectedRain, actualRain, 0.0001); + assertEquals(expectedSnow, actualSnow, 0.0001); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java index 6219252..39bcf4b 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_UnlOct24At0917Test.java @@ -12,104 +12,104 @@ import java.util.List; import static org.junit.Assert.assertEquals; public class Weather_UnlOct24At0917Test { - private OpenWeatherConnector connector; + private OpenWeatherConnector connector; - /* Demonstrates most fields; gust is distinct from wind speed; 3hr rain defaults to 1hr rain; no snow; multiple - weather categories */ + /* + * Demonstrates most fields; gust is distinct from wind speed; 3hr rain defaults + * to 1hr rain; no snow; multiple weather categories + */ - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("weather"); - connector.retrieveData("unl-oct24-0917.json"); - } + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("weather"); + connector.retrieveData("unl-oct24-0917.json"); + } - @Test - public void testLocation() { - double expectedLatitude = 40.8206; - double expectedLongitude = -96.6928; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } + @Test + public void testLocation() { + double expectedLatitude = 40.8206; + double expectedLongitude = -96.6928; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } - @Test - public void testDateTime() { + @Test + public void testDateTime() { // Date expectedValue = new Date(1635085053000L); - String expectedValue = "Sun Oct 24 09:17:33 CDT 2021"; - Date actualValue = connector.getTimestamp(); - assertEquals(expectedValue, actualValue.toString()); - } + String expectedValue = "Sun Oct 24 09:17:33 CDT 2021"; + Date actualValue = connector.getTimestamp(); + assertEquals(expectedValue, actualValue.toString()); + } - @Test - public void testWeather() { - List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of( - OpenWeatherConnector.WeatherCategory.MIST, - OpenWeatherConnector.WeatherCategory.RAIN, - OpenWeatherConnector.WeatherCategory.THUNDERSTORM - ); - List<String> expectedDescriptions = Arrays.asList("mist", "light rain", "thunderstorm with light rain"); - int expectedListSize = 3; - List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); - List<String> actualDescriptions = connector.getWeatherDescriptions(); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategories, actualCategories); - assertEquals(expectedDescriptions, actualDescriptions); - } + @Test + public void testWeather() { + List<OpenWeatherConnector.WeatherCategory> expectedCategories = List.of( + OpenWeatherConnector.WeatherCategory.MIST, OpenWeatherConnector.WeatherCategory.RAIN, + OpenWeatherConnector.WeatherCategory.THUNDERSTORM); + List<String> expectedDescriptions = Arrays.asList("mist", "light rain", "thunderstorm with light rain"); + int expectedListSize = 3; + List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); + List<String> actualDescriptions = connector.getWeatherDescriptions(); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategories, actualCategories); + assertEquals(expectedDescriptions, actualDescriptions); + } - @Test - public void testMainObservations() { - long expectedVisibility = 8047; - double expectedAmbientTemperature = 281.25; - long expectedHumidity = 96; - double expectedFeelsLikeTemperature = 279.92; - long expectedPressure = 1003; - long actualVisibility = connector.getVisibility(); - double actualAmbientTemperature = connector.getTemperature(); - long actualHumidity = connector.getHumidity(); - double actualFeelsLikeTemperature = connector.getFeelsLike(); - long actualPressure = connector.getPressure(); - assertEquals(expectedVisibility, actualVisibility); - assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); - assertEquals(expectedPressure, actualPressure); - } + @Test + public void testMainObservations() { + long expectedVisibility = 8047; + double expectedAmbientTemperature = 281.25; + long expectedHumidity = 96; + double expectedFeelsLikeTemperature = 279.92; + long expectedPressure = 1003; + long actualVisibility = connector.getVisibility(); + double actualAmbientTemperature = connector.getTemperature(); + long actualHumidity = connector.getHumidity(); + double actualFeelsLikeTemperature = connector.getFeelsLike(); + long actualPressure = connector.getPressure(); + assertEquals(expectedVisibility, actualVisibility); + assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); + assertEquals(expectedPressure, actualPressure); + } - @Test - public void testWinds() { - long expectedDirection = 43; - double expectedSpeed = 2.24; - double expectedGust = 4.92; - long actualDirection = connector.getWindDirection(); - double actualSpeed = connector.getWindSpeed(); - double actualGust = connector.getWindGust(); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); - } + @Test + public void testWinds() { + long expectedDirection = 43; + double expectedSpeed = 2.24; + double expectedGust = 4.92; + long actualDirection = connector.getWindDirection(); + double actualSpeed = connector.getWindSpeed(); + double actualGust = connector.getWindGust(); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); + } - @Test - public void testClouds() { - long expectedValue = 90; - long actualValue = connector.getCloudCover(); - assertEquals(expectedValue, actualValue); - } + @Test + public void testClouds() { + long expectedValue = 90; + long actualValue = connector.getCloudCover(); + assertEquals(expectedValue, actualValue); + } - @Test - public void testPrecipitation() { - double expected1HourRain = 0.11; - double expected3HourRain = 0.11; - double expected1HourSnow = 0.0; - double expected3HourSnow = 0.0; - double actual1HourRain = connector.getOneHourRainfall(); - double actual3HourRain = connector.getThreeHourRainfall(); - double actual1HourSnow = connector.getOneHourSnowfall(); - double actual3HourSnow = connector.getThreeHourSnowfall(); - assertEquals(expected1HourRain, actual1HourRain, 0.0001); - assertEquals(expected3HourRain, actual3HourRain, 0.0001); - assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); - assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); - } + @Test + public void testPrecipitation() { + double expected1HourRain = 0.11; + double expected3HourRain = 0.11; + double expected1HourSnow = 0.0; + double expected3HourSnow = 0.0; + double actual1HourRain = connector.getOneHourRainfall(); + double actual3HourRain = connector.getThreeHourRainfall(); + double actual1HourSnow = connector.getOneHourSnowfall(); + double actual3HourSnow = connector.getThreeHourSnowfall(); + assertEquals(expected1HourRain, actual1HourRain, 0.0001); + assertEquals(expected3HourRain, actual3HourRain, 0.0001); + assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); + assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); + } } diff --git a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java index 2a67669..9dcc044 100644 --- a/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java +++ b/src/test/java/edu/unl/cse/soft160/json_connections/Weather_WebsiteExampleTest.java @@ -12,96 +12,99 @@ import org.junit.Test; import static org.junit.Assert.*; public class Weather_WebsiteExampleTest { - private OpenWeatherConnector connector; + private OpenWeatherConnector connector; - /* Demonstrates most fields; gust defaults to wind speed; no rain or snow; one weather category */ + /* + * Demonstrates most fields; gust defaults to wind speed; no rain or snow; one + * weather category + */ - @Before - public void setup() throws IOException { - connector = new OpenWeatherConnector("weather"); - connector.retrieveData("website-example.json"); - } + @Before + public void setup() throws IOException { + connector = new OpenWeatherConnector("weather"); + connector.retrieveData("website-example.json"); + } - @Test - public void testLocation() { - double expectedLatitude = 37.39; - double expectedLongitude = -122.08; - double actualLatitude = connector.getLatitude(); - double actualLongitude = connector.getLongitude(); - assertEquals(expectedLatitude, actualLatitude, 0.0001); - assertEquals(expectedLongitude, actualLongitude, 0.0001); - } + @Test + public void testLocation() { + double expectedLatitude = 37.39; + double expectedLongitude = -122.08; + double actualLatitude = connector.getLatitude(); + double actualLongitude = connector.getLongitude(); + assertEquals(expectedLatitude, actualLatitude, 0.0001); + assertEquals(expectedLongitude, actualLongitude, 0.0001); + } - @Test - public void testDateTime() { + @Test + public void testDateTime() { // Date expectedValue = new Date(1560350645000L); - String expectedValue = "Wed Jun 12 09:44:05 CDT 2019"; - Date actualValue = connector.getTimestamp(); - assertEquals(expectedValue, actualValue.toString()); - } + String expectedValue = "Wed Jun 12 09:44:05 CDT 2019"; + Date actualValue = connector.getTimestamp(); + assertEquals(expectedValue, actualValue.toString()); + } - @Test - public void testWeather() { - OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.CLEAR; - String expectedDescription = "clear sky"; - int expectedListSize = 1; - List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); - List<String> actualDescriptions = connector.getWeatherDescriptions(); - assertEquals(expectedListSize, actualCategories.size()); - assertEquals(expectedListSize, actualDescriptions.size()); - assertEquals(expectedCategory, actualCategories.get(0)); - assertEquals(expectedDescription, actualDescriptions.get(0)); - } + @Test + public void testWeather() { + OpenWeatherConnector.WeatherCategory expectedCategory = OpenWeatherConnector.WeatherCategory.CLEAR; + String expectedDescription = "clear sky"; + int expectedListSize = 1; + List<OpenWeatherConnector.WeatherCategory> actualCategories = connector.getWeatherCategories(); + List<String> actualDescriptions = connector.getWeatherDescriptions(); + assertEquals(expectedListSize, actualCategories.size()); + assertEquals(expectedListSize, actualDescriptions.size()); + assertEquals(expectedCategory, actualCategories.get(0)); + assertEquals(expectedDescription, actualDescriptions.get(0)); + } - @Test - public void testMainObservations() { - long expectedVisibility = 16093; - double expectedAmbientTemperature = 282.55; - long expectedHumidity = 100; - double expectedFeelsLikeTemperature = 281.86; - long actualVisibility = connector.getVisibility(); - double actualAmbientTemperature = connector.getTemperature(); - long actualHumidity = connector.getHumidity(); - double actualFeelsLikeTemperature = connector.getFeelsLike(); - assertEquals(expectedVisibility, actualVisibility); - assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); - assertEquals(expectedHumidity, actualHumidity); - assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); - } + @Test + public void testMainObservations() { + long expectedVisibility = 16093; + double expectedAmbientTemperature = 282.55; + long expectedHumidity = 100; + double expectedFeelsLikeTemperature = 281.86; + long actualVisibility = connector.getVisibility(); + double actualAmbientTemperature = connector.getTemperature(); + long actualHumidity = connector.getHumidity(); + double actualFeelsLikeTemperature = connector.getFeelsLike(); + assertEquals(expectedVisibility, actualVisibility); + assertEquals(expectedAmbientTemperature, actualAmbientTemperature, 0.0001); + assertEquals(expectedHumidity, actualHumidity); + assertEquals(expectedFeelsLikeTemperature, actualFeelsLikeTemperature, 0.0001); + } - @Test - public void testWinds() { - long expectedDirection = 350; - double expectedSpeed = 1.5; - double expectedGust = 1.5; - long actualDirection = connector.getWindDirection(); - double actualSpeed = connector.getWindSpeed(); - double actualGust = connector.getWindGust(); - assertEquals(expectedDirection, actualDirection); - assertEquals(expectedSpeed, actualSpeed, 0.0001); - assertEquals(expectedGust, actualGust, 0.0001); - } + @Test + public void testWinds() { + long expectedDirection = 350; + double expectedSpeed = 1.5; + double expectedGust = 1.5; + long actualDirection = connector.getWindDirection(); + double actualSpeed = connector.getWindSpeed(); + double actualGust = connector.getWindGust(); + assertEquals(expectedDirection, actualDirection); + assertEquals(expectedSpeed, actualSpeed, 0.0001); + assertEquals(expectedGust, actualGust, 0.0001); + } - @Test - public void testClouds() { - long expectedValue = 1; - long actualValue = connector.getCloudCover(); - assertEquals(expectedValue, actualValue); - } + @Test + public void testClouds() { + long expectedValue = 1; + long actualValue = connector.getCloudCover(); + assertEquals(expectedValue, actualValue); + } - @Test - public void testPrecipitation() { - double expected1HourRain = 0.0; - double expected3HourRain = 0.0; - double expected1HourSnow = 0.0; - double expected3HourSnow = 0.0; - double actual1HourRain = connector.getOneHourRainfall(); - double actual3HourRain = connector.getThreeHourRainfall(); - double actual1HourSnow = connector.getOneHourSnowfall(); - double actual3HourSnow = connector.getThreeHourSnowfall(); - assertEquals(expected1HourRain, actual1HourRain, 0.0001); - assertEquals(expected3HourRain, actual3HourRain, 0.0001); - assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); - assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); - } + @Test + public void testPrecipitation() { + double expected1HourRain = 0.0; + double expected3HourRain = 0.0; + double expected1HourSnow = 0.0; + double expected3HourSnow = 0.0; + double actual1HourRain = connector.getOneHourRainfall(); + double actual3HourRain = connector.getThreeHourRainfall(); + double actual1HourSnow = connector.getOneHourSnowfall(); + double actual3HourSnow = connector.getThreeHourSnowfall(); + assertEquals(expected1HourRain, actual1HourRain, 0.0001); + assertEquals(expected3HourRain, actual3HourRain, 0.0001); + assertEquals(expected1HourSnow, actual1HourSnow, 0.0001); + assertEquals(expected3HourSnow, actual3HourSnow, 0.0001); + } } -- GitLab