From 20cad274e6a093cb2e6e4b42dda6fa024014f2b6 Mon Sep 17 00:00:00 2001 From: Justin Kaufman Date: Tue, 18 Aug 2015 15:55:35 -0500 Subject: [PATCH] Added Java client --- .gitignore | 2 +- README.md | 1 + client/java/README.md | 62 +++++++ client/java/build.gradle | 19 ++ client/java/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 53636 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + client/java/gradlew | 164 ++++++++++++++++++ .../main/java/us/xeserv/ponyapi/Episode.java | 84 +++++++++ .../java/us/xeserv/ponyapi/JsonDecoder.java | 42 +++++ .../java/us/xeserv/ponyapi/PonyApiClient.java | 158 +++++++++++++++++ .../us/xeserv/ponyapi/JsonDecoderTest.java | 92 ++++++++++ .../us/xeserv/ponyapi/PonyApiClientTest.java | 81 +++++++++ client/java/test.sh | 5 + 13 files changed, 715 insertions(+), 1 deletion(-) create mode 100644 client/java/README.md create mode 100644 client/java/build.gradle create mode 100644 client/java/gradle/wrapper/gradle-wrapper.jar create mode 100644 client/java/gradle/wrapper/gradle-wrapper.properties create mode 100644 client/java/gradlew create mode 100644 client/java/src/main/java/us/xeserv/ponyapi/Episode.java create mode 100644 client/java/src/main/java/us/xeserv/ponyapi/JsonDecoder.java create mode 100644 client/java/src/main/java/us/xeserv/ponyapi/PonyApiClient.java create mode 100644 client/java/src/test/java/us/xeserv/ponyapi/JsonDecoderTest.java create mode 100644 client/java/src/test/java/us/xeserv/ponyapi/PonyApiClientTest.java create mode 100644 client/java/test.sh diff --git a/.gitignore b/.gitignore index 5fe4b24..cd85e0b 100644 --- a/.gitignore +++ b/.gitignore @@ -59,5 +59,5 @@ docs/_build/ # PyBuilder target/ -ponyapi +# ponyapi nimcache diff --git a/README.md b/README.md index 61393ed..bbf612c 100644 --- a/README.md +++ b/README.md @@ -35,6 +35,7 @@ Clients - [Go](https://godoc.org/github.com/Xe/PonyAPI/client/go) - [Nim](https://github.com/Xe/PonyAPI/blob/master/client/nim/ponyapi.nim) [Docs](http://ponyapi.apps.xeserv.us/static/nim.html) - [Python](https://github.com/Xe/PonyAPI/blob/master/client/python/ponyapi.py) +- [Java](https://github.com/Xe/PonyAPI/client/java) Routes ------ diff --git a/client/java/README.md b/client/java/README.md new file mode 100644 index 0000000..a3113ed --- /dev/null +++ b/client/java/README.md @@ -0,0 +1,62 @@ +PonyAPI Java Client +=================== + +A Java client for accessing PonyAPI. Requires Java 8. + +Example Usage +------------- + +```java +package us.xeserv.examples; + +import us.xeserv.ponyapi.Episode; +import us.xeserv.ponyapi.PonyApiClient; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; + +public class PonyApiExample { + + public static void main(String[] args) throws IOException { + // Initialize a client with a custom API host + PonyApiClient client = new PonyApiClient("some.fqdn.here"); // defaults to port 80 + client = new PonyApiClient("some.fqdn.here", 8080); // with a custom port number + // Initialize a client using http://ponyapi.apps.xeserv.us/ as the API ohst + client = new PonyApiClient(); + + // Get a list of all the episodes + List allEpisodes = client.all(); + + // Get the newest episode + Episode newestEpisode = client.newest(); + + // Get information about an episode + String name = newestEpisode.name; + Instant airDate = newestEpisode.airDate; + int seasonNumber = newestEpisode.season; + int episodeNumber = newestEpisode.episode; + boolean isMovie = newestEpisode.isMovie; + + // Get all episodes in a season + List season = client.getSeason(1); + + // Get all movies + List movies = client.getMovies(); + + // Get a specific episode by season and episode number + Episode specificEpisode = client.getEpisode(1, 13); + + // Get a specific movie by movie number + Episode specificMovie = client.getMovie(1); + + // Get a random movie or movie number + Episode random = client.random(); + + // Get a list of all episodes and movies matching a query + List queryResults = client.search("Owl's Well"); // returns Owl's Well That Ends Well + + } + +} +``` \ No newline at end of file diff --git a/client/java/build.gradle b/client/java/build.gradle new file mode 100644 index 0000000..2196fa9 --- /dev/null +++ b/client/java/build.gradle @@ -0,0 +1,19 @@ +group 'us.xeserv' +version '1.0' + +apply plugin: 'java' + +sourceCompatibility = 1.8 +targetCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile "com.google.code.gson:gson:+" + compile "org.apache.httpcomponents:httpclient:+" + compile "org.apache.httpcomponents:fluent-hc:+" + compile "com.google.guava:guava:+" + testCompile "junit:junit:+" +} \ No newline at end of file diff --git a/client/java/gradle/wrapper/gradle-wrapper.jar b/client/java/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..fd7e590e5154e82211909581e71018372134fb27 GIT binary patch literal 53636 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⪚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 literal 0 HcmV?d00001 diff --git a/client/java/gradle/wrapper/gradle-wrapper.properties b/client/java/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..9dd18d3 --- /dev/null +++ b/client/java/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Tue Aug 18 15:13:15 CDT 2015 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-2.6-bin.zip diff --git a/client/java/gradlew b/client/java/gradlew new file mode 100644 index 0000000..91a7e26 --- /dev/null +++ b/client/java/gradlew @@ -0,0 +1,164 @@ +#!/usr/bin/env bash + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn ( ) { + echo "$*" +} + +die ( ) { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; +esac + +# For Cygwin, ensure paths are in UNIX format before anything is touched. +if $cygwin ; then + [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` +fi + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >&- +APP_HOME="`pwd -P`" +cd "$SAVED" >&- + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules +function splitJvmOpts() { + JVM_OPTS=("$@") +} +eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS +JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" + +exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" diff --git a/client/java/src/main/java/us/xeserv/ponyapi/Episode.java b/client/java/src/main/java/us/xeserv/ponyapi/Episode.java new file mode 100644 index 0000000..ad1d7dc --- /dev/null +++ b/client/java/src/main/java/us/xeserv/ponyapi/Episode.java @@ -0,0 +1,84 @@ +package us.xeserv.ponyapi; + +import java.time.Instant; +import java.util.Objects; + +/** + * The {@code Episode} class represents My Little Pony episode or movie information returned by PonyAPI. + *

+ * Episodes are immutable; they represent data returned from the API and cannot be changed after they are created. + *

+ * Movie data stored in an {@code Episode} object are referred to by the season number 99. Their episode number refers + * to the order of their release starting with 1. + * + * @author Justin Kaufman + * @since 1.0 + */ +public class Episode { + + /** + * The name of the episode or movie. + */ + public final String name; + + /** + * The season of the episode, or 99 if it is a movie. + */ + public final int season; + + /** + * The episode or movie number. + */ + public final int episode; + + /** + * The air date. + */ + public final Instant airDate; + + /** + * True if this episode represents a movie, false otherwise. + */ + public final boolean isMovie; + + protected Episode(String name, int season, int episode, long airDate, boolean isMovie) { + this.name = name; + this.season = season; + this.episode = episode; + this.airDate = Instant.ofEpochSecond(airDate); + this.isMovie = isMovie; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Episode rhs = (Episode) obj; + return Objects.equals(name, rhs.name) + && Objects.equals(season, rhs.season) + && Objects.equals(episode, rhs.episode) + && Objects.equals(airDate, rhs.airDate) + && Objects.equals(isMovie, rhs.isMovie); + } + + @Override + public int hashCode() { + return Objects.hash(name, season, episode, airDate, isMovie); + } + + @Override + public String toString() { + return "{\n" + + "\t\"name\": \"" + name + "\",\n" + + "\t\"air_date\": " + airDate.getEpochSecond() + ",\n" + + "\t\"season\": " + season + ",\n" + + "\t\"episode\": " + episode + ",\n" + + "\t\"is_movie\": " + isMovie + "\n" + + "}"; + } + +} \ No newline at end of file diff --git a/client/java/src/main/java/us/xeserv/ponyapi/JsonDecoder.java b/client/java/src/main/java/us/xeserv/ponyapi/JsonDecoder.java new file mode 100644 index 0000000..d836929 --- /dev/null +++ b/client/java/src/main/java/us/xeserv/ponyapi/JsonDecoder.java @@ -0,0 +1,42 @@ +package us.xeserv.ponyapi; + +import com.google.gson.*; + +import java.util.ArrayList; +import java.util.List; + +class JsonDecoder { + + private static final Gson gson; + static { + GsonBuilder gsonBuilder = new GsonBuilder(); + gsonBuilder.registerTypeAdapter(Episode.class, (JsonDeserializer) (json, typeOfT, context) -> { + JsonObject jsonObject = json.getAsJsonObject(); + return new Episode( + jsonObject.get("name").getAsString(), + jsonObject.get("season").getAsInt(), + jsonObject.get("episode").getAsInt(), + jsonObject.get("air_date").getAsLong(), + jsonObject.get("is_movie").getAsBoolean() + ); + }); + gson = gsonBuilder.create(); + } + + protected static Episode fromJson(String json) { + JsonObject wrapper = (JsonObject) new JsonParser().parse(json); + JsonObject payload = wrapper.get("episode").getAsJsonObject(); + return gson.fromJson(payload, Episode.class); + } + + protected static List listFromJson(String json) { + List list = new ArrayList<>(); + JsonObject wrapper = (JsonObject) new JsonParser().parse(json); + JsonArray payload = wrapper.get("episodes").getAsJsonArray(); + for (JsonElement episode : payload) { + list.add(gson.fromJson(episode, Episode.class)); + } + return list; + } + +} diff --git a/client/java/src/main/java/us/xeserv/ponyapi/PonyApiClient.java b/client/java/src/main/java/us/xeserv/ponyapi/PonyApiClient.java new file mode 100644 index 0000000..63aaa37 --- /dev/null +++ b/client/java/src/main/java/us/xeserv/ponyapi/PonyApiClient.java @@ -0,0 +1,158 @@ +package us.xeserv.ponyapi; + +import com.google.common.base.Strings; +import org.apache.http.HttpResponse; +import org.apache.http.client.fluent.Request; +import org.apache.http.util.EntityUtils; + +import java.io.IOException; +import java.net.URLEncoder; +import java.util.List; + +/** + * The {@code PonyApiClient} class provides an interface between Java code that uses this library and PonyAPI. + *

+ * This client is able to retrieve information about the show My Little Pony: Friendship is Magic. + * + * @author Justin Kaufman + * @since 1.0 + */ +public class PonyApiClient { + + private final String host; + + /** + * The default constructor initializes a client instance that uses http://ponyapi.apps.xeserv.us/ as the API source. + */ + public PonyApiClient() { + this("ponyapi.apps.xeserv.us"); + } + + /** + * Accepts a FQDN (and optionally port) running the PonyAPI service. + * @param host a FQDN running the PonyAPI service + */ + public PonyApiClient(String host) { + this.host = host; + } + + /** + * Returns a list of all episodes and movies. + * @return a list of all episodes and movies + * @throws IOException if there is an error accessing the service + */ + public List all() throws IOException { + return JsonDecoder.listFromJson(asJson(get("/all"))); + } + + /** + * Returns the newest episode or movie aired. + * @return the newest episode or movie aired + * @throws IOException if there is an error accessing the service + */ + public Episode newest() throws IOException { + return JsonDecoder.fromJson(asJson(get("/newest"))); + } + + /** + * Returns the episode or movie that most recently aired. + * @return the episode or movie that most recently aired + * @throws IOException if there is an error accessing the service + */ + public Episode lastAired() throws IOException { + return JsonDecoder.fromJson(asJson(get("/last_aired"))); + } + + /** + * Returns all information about episodes in a given season number. + * @param season the season number + * @return all information about episodes in a given season number + * @throws IOException if there is an error accessing the service + */ + public List getSeason(int season) throws IOException { + HttpResponse response = get("/season/" + season); + if (statusCode(response) == 404) { + return null; + } + return JsonDecoder.listFromJson(asJson(response)); + } + + /** + * Returns all information about movies. + * @return all information about movies + * @throws IOException if there is an error accessing the service + */ + public List getMovies() throws IOException { + return JsonDecoder.listFromJson(asJson(get("/season/99"))); + } + + /** + * Returns all information about the episode with the given season and episode number. + * @param season the season number + * @param episode the episode number + * @return all information about the episode with the given season and episode number + * @throws IOException if there is an error accessing the service + */ + public Episode getEpisode(int season, int episode) throws IOException { + HttpResponse response = get("/season/" + season + "/episode/" + episode); + if (statusCode(response) == 404) { + return null; + } + return JsonDecoder.fromJson(asJson(response)); + } + + /** + * Returns all information about the movie with the given movie number. + * @param movie the movie number + * @return all information about the movie with the given movie number + * @throws IOException if there is an error accessing the service + */ + public Episode getMovie(int movie) throws IOException { + HttpResponse response = get("/season/99/episode/" + movie); + if (statusCode(response) == 404) { + return null; + } + return JsonDecoder.fromJson(asJson(response)); + } + + /** + * Returns a random episode or movie from the record. + * @return a random episode or movie from the record + * @throws IOException if there is an error accessing the service + */ + public Episode random() throws IOException { + String json = asJson(get("/random")); + return JsonDecoder.fromJson(json); + } + + /** + * Returns a list of episodes which contain the query in its name. + * @param query a case-independent, non-empty {@code String} + * @return a list of episodes which contain the query in its name + * @throws IOException if there is an error accessing the service + * @throws IllegalArgumentException if the query is null or empty + */ + public List search(String query) throws IOException { + if (Strings.isNullOrEmpty(query)) { + throw new IllegalArgumentException("A search query is required."); + } + String json = asJson(get("/search?q=" + URLEncoder.encode(query, "UTF-8"))); + return JsonDecoder.listFromJson(json); + } + + private HttpResponse get(String path) throws IOException { + return Request.Get("http://" + host + path) + .userAgent("PonyApi Java Client 1.0") + .execute() + .returnResponse(); + } + + private String asJson(HttpResponse response) throws IOException { + return EntityUtils.toString(response.getEntity()); + } + + private int statusCode(HttpResponse response) throws IOException { + return response.getStatusLine().getStatusCode(); + } + +} diff --git a/client/java/src/test/java/us/xeserv/ponyapi/JsonDecoderTest.java b/client/java/src/test/java/us/xeserv/ponyapi/JsonDecoderTest.java new file mode 100644 index 0000000..985f685 --- /dev/null +++ b/client/java/src/test/java/us/xeserv/ponyapi/JsonDecoderTest.java @@ -0,0 +1,92 @@ +package us.xeserv.ponyapi; + +import org.junit.Test; + +import java.time.Instant; +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class JsonDecoderTest { + + @Test + public void episodeTest() { + String json = "{\n" + + "\t\"episode\":\n" + + "\t{\n" + + "\t\t\"name\": \"Friendship is Magic Part 1\",\n" + + "\t\t\"air_date\": 1286735400,\n" + + "\t\t\"season\": 1,\n" + + "\t\t\"episode\": 1,\n" + + "\t\t\"is_movie\": false\n" + + "\t}\n" + + "}"; + + Episode episode = JsonDecoder.fromJson(json); + assertEquals("Friendship is Magic Part 1", episode.name); + assertEquals(Instant.ofEpochSecond(1286735400), episode.airDate); + assertEquals(1, episode.season); + assertEquals(1, episode.episode); + assertEquals(false, episode.isMovie); + } + + @Test + public void movieTest() { + String json = "{\n" + + "\t\"episode\":\n" + + "\t{\n" + + "\t\t\"name\": \"Equestria Girls\",\n" + + "\t\t\"air_date\": 1371340800,\n" + + "\t\t\"season\": 99,\n" + + "\t\t\"episode\": 1,\n" + + "\t\t\"is_movie\": true\n" + + "\t}\n" + + "}"; + + Episode episode = JsonDecoder.fromJson(json); + assertEquals("Equestria Girls", episode.name); + assertEquals(Instant.ofEpochSecond(1371340800), episode.airDate); + assertEquals(99, episode.season); + assertEquals(1, episode.episode); + assertEquals(true, episode.isMovie); + } + + @Test + public void multipleTest() { + String json = "{\n" + + "\t\"episodes\": [\n" + + "\t\t{\n" + + "\t\t\t\"name\": \"Friendship is Magic Part 1\",\n" + + "\t\t\t\"air_date\": 1286735400,\n" + + "\t\t\t\"season\": 1,\n" + + "\t\t\t\"episode\": 1,\n" + + "\t\t\t\"is_movie\": false\n" + + "\t\t},\n" + + "\t\t{\n" + + "\t\t\t\"name\": \"Equestria Girls\",\n" + + "\t\t\t\"air_date\": 1371340800,\n" + + "\t\t\t\"season\": 99,\n" + + "\t\t\t\"episode\": 1,\n" + + "\t\t\t\"is_movie\": true\n" + + "\t\t}\n" + + "\t]\n" + + "}"; + + List episodes = JsonDecoder.listFromJson(json); + assertEquals(2, episodes.size()); + + Episode episode1 = episodes.get(0); + assertEquals("Friendship is Magic Part 1", episode1.name); + assertEquals(Instant.ofEpochSecond(1286735400), episode1.airDate); + assertEquals(1, episode1.season); + assertEquals(1, episode1.episode); + assertEquals(false, episode1.isMovie); + + Episode episode2 = episodes.get(1); + assertEquals("Equestria Girls", episode2.name); + assertEquals(Instant.ofEpochSecond(1371340800), episode2.airDate); + assertEquals(99, episode2.season); + assertEquals(1, episode2.episode); + assertEquals(true, episode2.isMovie); + } +} diff --git a/client/java/src/test/java/us/xeserv/ponyapi/PonyApiClientTest.java b/client/java/src/test/java/us/xeserv/ponyapi/PonyApiClientTest.java new file mode 100644 index 0000000..2eca18e --- /dev/null +++ b/client/java/src/test/java/us/xeserv/ponyapi/PonyApiClientTest.java @@ -0,0 +1,81 @@ +package us.xeserv.ponyapi; + +import org.junit.Test; + +import java.io.IOException; +import java.time.Instant; +import java.util.List; + +import static org.junit.Assert.*; + +public class PonyApiClientTest { + + private PonyApiClient client = new PonyApiClient(); + + @Test + public void allTest() throws Exception { + List list = client.all(); + assertFalse(list.isEmpty()); + } + + @Test + public void newestTest() throws IOException { + Episode episode = client.newest(); + assertNotNull(episode); + } + + @Test + public void lastAiredTest() throws IOException { + Episode episode = client.lastAired(); + assertNotNull(episode); + } + + @Test + public void getSeasonTest() throws IOException { + List list = client.getSeason(98); + assertEquals(null, list); + list = client.getSeason(1); + assertEquals(26, list.size()); + } + + @Test + public void getMoviesTest() throws IOException { + List list = client.getMovies(); + assertFalse(list.isEmpty()); + } + + @Test + public void getEpisodeTest() throws IOException { + Episode episode = client.getEpisode(1, 1); + assertEquals("Friendship is Magic Part 1", episode.name); + assertEquals(Instant.ofEpochSecond(1286735400), episode.airDate); + assertEquals(1, episode.season); + assertEquals(1, episode.episode); + assertEquals(false, episode.isMovie); + } + + @Test + public void getMovieTest() throws IOException { + Episode episode = client.getMovie(1); + assertEquals("Equestria Girls", episode.name); + assertEquals(Instant.ofEpochSecond(1371340800), episode.airDate); + assertEquals(99, episode.season); + assertEquals(1, episode.episode); + assertEquals(true, episode.isMovie); + } + + @Test + public void randomTest() throws IOException { + Episode episode = client.random(); + assertNotNull(episode); + } + + @Test + public void searchTest() throws IOException { + List episodes = client.search("Owl's Well"); + assertEquals(1, episodes.size()); + Episode episode = episodes.get(0); + assertEquals("Owl's Well That Ends Well", episode.name); + } + +} diff --git a/client/java/test.sh b/client/java/test.sh new file mode 100644 index 0000000..9150561 --- /dev/null +++ b/client/java/test.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +set -e + +./gradlew test \ No newline at end of file