diff --git a/src/main/java/com/jcabi/github/RepositoryStatistics.java b/src/main/java/com/jcabi/github/RepositoryStatistics.java index c46d20ca3..1bb55c6b7 100644 --- a/src/main/java/com/jcabi/github/RepositoryStatistics.java +++ b/src/main/java/com/jcabi/github/RepositoryStatistics.java @@ -30,6 +30,7 @@ package com.jcabi.github; import java.io.IOException; +import java.time.ZonedDateTime; import java.util.Arrays; import java.util.Map; import java.util.stream.Collectors; @@ -44,17 +45,6 @@ * @author Volodya Lombrozo (volodya.lombrozo@gmail.com) * @version $Id $ * @since 1.8.0 - * @todo #1660:90min Add RepositoryStatistics.Smart. - * Implement RepositoryStatistics.Smart and use it to retrieve repository - * statistics with the following methods: - * - RepositoryStatistics.Smart#language() - * - RepositoryStatistics.Smart#forksCount() - * - RepositoryStatistics.Smart#stargazers() - * - RepositoryStatistics.Smart#watchers() - * - RepositoryStatistics.Smart#size() - * - RepositoryStatistics.Smart#openIssues() - * In other words, it would be convenient to have particular methods with - * understandable names instead of using toMap() method. */ public final class RepositoryStatistics { @@ -162,6 +152,14 @@ private enum KEY { this.key = json; } + /** + * Getter for the key. + * @return The key of the JSON object returned by the GitHub API. + */ + public String getKey() { + return this.key; + } + /** * Extracts the JSON object returned by the GitHub to a map entry. * @param object The JSON object returned by the GitHub API. @@ -188,5 +186,114 @@ Object value(final JsonObject object) { return result; } } + + /** + * Smart RepositoryStatistics. + * + * @version $Id $ + * @author Volodya Lombrozo (volodya.lombrozo@gmail.com) + * @since 1.8.0 + */ + public static final class Smart { + + /** + * Repository statistics. + */ + private final transient RepositoryStatistics stats; + + /** + * Public ctor. + * @param repo Repository. + */ + public Smart(final Repo repo) { + this(new RepositoryStatistics(repo)); + } + + /** + * Public ctor. + * @param statistics Repository statistics. + */ + public Smart(final RepositoryStatistics statistics) { + this.stats = statistics; + } + + /** + * Number of forks of this repository. + * @return Number of forks + * @throws IOException If there is any I/O problem + */ + public int forks() throws IOException { + return this.integer(KEY.FORKS_COUNT); + } + + /** + * Number of users who have starred this repository. + * @return Number of stargazers + * @throws IOException If there is any I/O problem + */ + public int stargazers() throws IOException { + return this.integer(KEY.STARGAZERS_COUNT); + } + + /** + * Number of users watching the repository. + * @return Number of watchers + * @throws IOException If there is any I/O problem + */ + public int watchers() throws IOException { + return this.integer(KEY.WATCHERS_COUNT); + } + + /** + * The size of the repository. + * @return Size of the repository + * @throws IOException If there is any I/O problem + */ + public int size() throws IOException { + return this.integer(KEY.SIZE); + } + + /** + * The number of open issues in this repository. + * @return Number of open issues + * @throws IOException If there is any I/O problem + */ + public int openIssues() throws IOException { + return this.integer(KEY.OPEN_ISSUES_COUNT); + } + + /** + * The time the repository was created. + * @return Time the repository was created + * @throws IOException If there is any I/O problem + */ + public ZonedDateTime created() throws IOException { + return this.datetime(KEY.CREATED_AT); + } + + /** + * Parses integer from JSON. + * @param key Json key. + * @return Integer value. + * @throws IOException If there is any I/O problem + */ + private int integer(final KEY key) throws IOException { + return Integer.parseInt( + String.valueOf(this.stats.toMap().get(key.getKey())) + ); + } + + /** + * Parses datetime from JSON. + * @param key Json key. + * @return Datetime value. + * @throws IOException If there is any I/O problem + */ + private ZonedDateTime datetime(final KEY key) throws IOException { + return ZonedDateTime.parse( + String.valueOf(this.stats.toMap().get(key.getKey())) + ); + } + } } diff --git a/src/test/java/com/jcabi/github/RepositoryStatisticsTest.java b/src/test/java/com/jcabi/github/RepositoryStatisticsTest.java index 0273beeae..dfb923ba1 100644 --- a/src/test/java/com/jcabi/github/RepositoryStatisticsTest.java +++ b/src/test/java/com/jcabi/github/RepositoryStatisticsTest.java @@ -31,6 +31,7 @@ import com.jcabi.github.mock.MkGithub; import java.io.IOException; +import java.time.ZonedDateTime; import java.util.Map; import javax.json.Json; import org.hamcrest.MatcherAssert; @@ -49,9 +50,99 @@ * MkRepo should return different types like integer, double, long, * etc. When it is implemented, we can replace strings with concrete * types and remove that puzzle. + * @todo #1663:90min Refactor RepositoryStatisticsTest. + * RepositoryStatisticsTest has too many boilerplate code. Also it + * has repeated variables and constants. Refactor it to make it more + * readable and maintainable. Moreover all this variables don't follow + * PMD and Checkstyle rules. When it is done, remove this puzzle and + * all the checkstyle and PMD suppressions. + * @checkstyle StaticVariableNameCheck (1000 lines) + * @checkstyle MagicNumberCheck (1000 lines) + * @checkstyle LineLengthCheck (2 lines) */ +@SuppressWarnings({"PMD.SuspiciousConstantFieldName", "PMD.VariableNamingConventions"}) public final class RepositoryStatisticsTest { + /** + * Forks key in JSON. + */ + private static final String FORKS_KEY = "forks_count"; + + /** + * Forks JSON value. + */ + private static final int FORKS_VALUE = 1; + + /** + * Language key in JSON. + */ + private static final String LANGUAGE_KEY = "language"; + + /** + * Language value in JSON. + */ + private static String LANGUAGE_VALUE = "java"; + + /** + * Stargazers key in JSON. + */ + private static String STARGAZERS_KEY = "stargazers_count"; + + /** + * Stargazers value in JSON. + */ + private static int STARGAZERS_VALUE = 2; + + /** + * Watchers key in JSON. + */ + private static String WATCHERS_KEY = "watchers_count"; + + /** + * Watchers value in JSON. + */ + private static int WATCHERS_VALUE = 3; + + /** + * Size key in JSON. + */ + private static String SIZE_KEY = "size"; + + /** + * Size value in JSON. + */ + private static int SIZE_VALUE = 4; + + /** + * Issues key in JSON. + */ + private static String ISSUES_KEY = "open_issues_count"; + + /** + * Issues value in JSON. + */ + private static int ISSUES_VALUE = 5; + + /** + * Created key in JSON. + */ + private static String CREATED_KEY = "created_at"; + + /** + * Created value in JSON. + */ + private static String CREATED_VALUE = "2011-01-26T19:14:43Z"; + + /** + * Updated key in JSON. + */ + private static String UPDATED_KEY = "updated_at"; + + /** + * Updated value in JSON. + */ + private static String UPDATED_VALUE = "2012-01-26T19:14:43Z"; + /** * Checks that RepositryStatistics can convert all values to a map. * @throws IOException If some problem with I/O happened. @@ -59,49 +150,168 @@ public final class RepositoryStatisticsTest { @Test public void retrievesBasicStatisticsFromRepo() throws IOException { - final String language = "language"; - final String forks = "forks_count"; - final String stargazers = "stargazers_count"; - final String watchers = "watchers_count"; - final String size = "size"; - final String issues = "open_issues_count"; - final String created = "created_at"; - final String updated = "updated_at"; - final String date = "2011-01-26T19:14:43Z"; - final String java = "java"; MatcherAssert.assertThat( "We expect to have basic statistics from repo", - new RepositoryStatistics( - new MkGithub() - .repos() - .create( - new Repos.RepoCreate("volodya-lombrozo", false) - .with(language, Json.createValue(java)) - .with(forks, Json.createValue(1)) - .with(stargazers, Json.createValue(2)) - .with(watchers, Json.createValue(Integer.MAX_VALUE)) - .with(size, Json.createValue(Integer.MIN_VALUE)) - .with(issues, Json.createValue(1 + 1 + 1)) - .with(created, Json.createValue(date)) - .with(updated, Json.createValue(date)) - ) - ).toMap(), + new RepositoryStatistics(this.repo()).toMap(), Matchers.>allOf( - Matchers.hasEntry(language, java), - Matchers.hasEntry(forks, "1"), - Matchers.hasEntry(stargazers, "2"), Matchers.hasEntry( - watchers, - String.valueOf(Integer.MAX_VALUE) + RepositoryStatisticsTest.LANGUAGE_KEY, + RepositoryStatisticsTest.LANGUAGE_VALUE + ), + Matchers.hasEntry( + RepositoryStatisticsTest.FORKS_KEY, + String.valueOf( + RepositoryStatisticsTest.FORKS_VALUE + ) + ), + Matchers.hasEntry( + RepositoryStatisticsTest.STARGAZERS_KEY, + String.valueOf( + RepositoryStatisticsTest.STARGAZERS_VALUE + ) + ), + Matchers.hasEntry( + RepositoryStatisticsTest.WATCHERS_KEY, + String.valueOf( + RepositoryStatisticsTest.WATCHERS_VALUE + ) + ), + Matchers.hasEntry( + RepositoryStatisticsTest.SIZE_KEY, + String.valueOf( + RepositoryStatisticsTest.SIZE_VALUE + ) + ), + Matchers.hasEntry( + RepositoryStatisticsTest.ISSUES_KEY, + String.valueOf( + RepositoryStatisticsTest.ISSUES_VALUE + ) ), Matchers.hasEntry( - size, - String.valueOf(Integer.MIN_VALUE) + RepositoryStatisticsTest.CREATED_KEY, + RepositoryStatisticsTest.CREATED_VALUE ), - Matchers.hasEntry(issues, "3"), - Matchers.hasEntry(created, date), - Matchers.hasEntry(updated, date) + Matchers.hasEntry( + RepositoryStatisticsTest.UPDATED_KEY, + RepositoryStatisticsTest.UPDATED_VALUE + ) + ) + ); + } + + /** + * Checks that RepositryStatistics.Smart can retrieve all values. + * @throws IOException If some problem with I/O happened. + */ + @Test + public void retrievesSmartStatistics() throws IOException { + final RepositoryStatistics.Smart smart = + new RepositoryStatistics.Smart(this.repo()); + MatcherAssert.assertThat( + "Forks should be equal to 1", + smart.forks(), + Matchers.equalTo( + RepositoryStatisticsTest.FORKS_VALUE + ) + ); + MatcherAssert.assertThat( + "Stargazers should be equal to 2", + smart.stargazers(), + Matchers.equalTo( + RepositoryStatisticsTest.STARGAZERS_VALUE ) ); + MatcherAssert.assertThat( + "Watchers should be equal to 3", + smart.watchers(), + Matchers.equalTo( + RepositoryStatisticsTest.WATCHERS_VALUE + ) + ); + MatcherAssert.assertThat( + "Size should be equal to 4", + smart.size(), + Matchers.equalTo( + RepositoryStatisticsTest.SIZE_VALUE + ) + ); + MatcherAssert.assertThat( + "Issues should be equal to 5", + smart.openIssues(), + Matchers.equalTo( + RepositoryStatisticsTest.ISSUES_VALUE + ) + ); + MatcherAssert.assertThat( + "Created date should be equal to 2011-01-26T19:14:43Z", + smart.created(), + Matchers.equalTo( + ZonedDateTime.parse( + RepositoryStatisticsTest.CREATED_VALUE + ) + ) + ); + } + + /** + * Creates mock repo. + * @return Repo + * @throws IOException If some problem with I/O happened. + */ + private Repo repo() throws IOException { + return new MkGithub() + .repos() + .create( + new Repos.RepoCreate("volodya-lombrozo", false) + .with( + RepositoryStatisticsTest.LANGUAGE_KEY, + Json.createValue( + RepositoryStatisticsTest.LANGUAGE_VALUE + ) + ) + .with( + RepositoryStatisticsTest.FORKS_KEY, + Json.createValue( + RepositoryStatisticsTest.FORKS_VALUE + ) + ) + .with( + RepositoryStatisticsTest.STARGAZERS_KEY, + Json.createValue( + RepositoryStatisticsTest.STARGAZERS_VALUE + ) + ) + .with( + RepositoryStatisticsTest.WATCHERS_KEY, + Json.createValue( + RepositoryStatisticsTest.WATCHERS_VALUE + ) + ) + .with( + RepositoryStatisticsTest.SIZE_KEY, + Json.createValue( + RepositoryStatisticsTest.SIZE_VALUE + ) + ) + .with( + RepositoryStatisticsTest.ISSUES_KEY, + Json.createValue( + RepositoryStatisticsTest.ISSUES_VALUE + ) + ) + .with( + RepositoryStatisticsTest.CREATED_KEY, + Json.createValue( + RepositoryStatisticsTest.CREATED_VALUE + ) + ) + .with( + RepositoryStatisticsTest.UPDATED_KEY, + Json.createValue( + RepositoryStatisticsTest.UPDATED_VALUE + ) + ) + ); } }