diff --git a/src/main/java/com/jcabi/github/Check.java b/src/main/java/com/jcabi/github/Check.java index 18719626f..7def3b63a 100644 --- a/src/main/java/com/jcabi/github/Check.java +++ b/src/main/java/com/jcabi/github/Check.java @@ -29,6 +29,10 @@ */ package com.jcabi.github; +import java.io.IOException; +import java.util.Arrays; +import java.util.Locale; + /** * Github check. * @@ -42,7 +46,187 @@ public interface Check { /** * Checks whether Check was successful. * @return True if Check was successful. + * @throws IOException If there is any I/O problem. + */ + boolean successful() throws IOException; + + /** + * Check status. + * You can read more about it + * @checkstyle LineLengthCheck (1 lines) + * here + */ + enum Status { + /** + * Queued. + */ + QUEUED("queued"), + + /** + * In progress. + */ + IN_PROGRESS("in_progress"), + + /** + * Completed. + */ + COMPLETED("completed"); + + /** + * Status. + */ + private final String status; + + /** + * Ctor. + * @param stat Status. + */ + Status(final String stat) { + this.status = stat; + } + + /** + * Status. + * @return Status. + */ + public String value() { + return this.status; + } + + /** + * Get status from string. + * @param value String value. + * @return Status. + */ + public static Status fromString(final String value) { + return Arrays.stream(Status.values()) + .filter(stat -> stat.same(value)) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException( + String.format("Invalid value %s for status", value) + ) + ); + } + + /** + * Check if check is finished. + * @return True if check is finished. + */ + boolean finished() { + return this == Status.COMPLETED; + } + + /** + * Check if status is the same as value. + * @param value Value. + * @return True if status is the same as value. + */ + boolean same(final String value) { + return this.status.equals(value.toLowerCase(Locale.ROOT)); + } + } + + /** + * Check conclusion. + * You can read more about it + * @checkstyle LineLengthCheck (1 lines) + * here */ - boolean successful(); + enum Conclusion { + + /** + * Action required. + */ + ACTION_REQUIRED("action_required"), + + /** + * Cancelled. + */ + CANCELLED("cancelled"), + + /** + * Failure. + */ + FAILURE("failure"), + + /** + * Neutral. + */ + NEUTRAL("neutral"), + + /** + * Success. + */ + SUCCESS("success"), + + /** + * Skipped. + */ + SKIPPED("skipped"), + + /** + * Stale. + */ + STALE("stale"), + + /** + * Timed out. + */ + TIMED_OUT("timed_out"); + + /** + * Conclusion. + */ + private final String conclusion; + + /** + * Ctor. + * @param con Conclusion. + */ + Conclusion(final String con) { + this.conclusion = con; + } + + /** + * Get conclusion from string. + * @param value String value. + * @return Conclusion. + */ + public static Conclusion fromString(final String value) { + return Arrays.stream(Conclusion.values()) + .filter(stat -> stat.same(value)) + .findFirst() + .orElseThrow( + () -> new IllegalArgumentException( + String.format("Invalid value %s for conclusion", value) + ) + ); + } + + /** + * Conclusion. + * @return Conclusion. + */ + public String value() { + return this.conclusion; + } + + /** + * Check if check is successful. + * @return True if check is successful. + */ + boolean successful() { + return this == Conclusion.SUCCESS; + } + /** + * Check if conclusion is the same as value. + * @param value Value to compare. + * @return True if conclusion is the same as value. + */ + boolean same(final String value) { + return this.conclusion.equals(value.toLowerCase(Locale.ROOT)); + } + } } diff --git a/src/main/java/com/jcabi/github/RtCheck.java b/src/main/java/com/jcabi/github/RtCheck.java index 2872e9709..fbb2f1e16 100644 --- a/src/main/java/com/jcabi/github/RtCheck.java +++ b/src/main/java/com/jcabi/github/RtCheck.java @@ -29,9 +29,6 @@ */ package com.jcabi.github; -import java.util.Arrays; -import java.util.Locale; - /** * Github check. * @@ -57,10 +54,7 @@ class RtCheck implements Check { * @param stat Status. * @param conc Conclusion. */ - RtCheck( - final String stat, - final String conc - ) { + RtCheck(final String stat, final String conc) { this(Status.fromString(stat), Conclusion.fromString(conc)); } @@ -81,168 +75,4 @@ class RtCheck implements Check { public boolean successful() { return this.status.finished() && this.conclusion.successful(); } - - /** - * Check status. - * You can read more about it - * @checkstyle LineLengthCheck (1 lines) - * here - */ - enum Status { - /** - * Queued. - */ - QUEUED("queued"), - - /** - * In progress. - */ - IN_PROGRESS("in_progress"), - - /** - * Completed. - */ - COMPLETED("completed"); - - /** - * Status. - */ - private final String status; - - /** - * Ctor. - * @param stat Status. - */ - Status(final String stat) { - this.status = stat; - } - - /** - * Check if check is finished. - * @return True if check is finished. - */ - boolean finished() { - return this == Status.COMPLETED; - } - - /** - * Get status from string. - * @param value String value. - * @return Status. - */ - static Status fromString(final String value) { - return Arrays.stream(Status.values()) - .filter(stat -> stat.same(value)) - .findFirst() - .orElseThrow( - () -> new IllegalArgumentException( - String.format("Invalid value %s for status", value) - ) - ); - } - - /** - * Check if status is the same as value. - * @param value Value. - * @return True if status is the same as value. - */ - boolean same(final String value) { - return this.status.equals(value.toLowerCase(Locale.ROOT)); - } - } - - /** - * Check conclusion. - * You can read more about it - * @checkstyle LineLengthCheck (1 lines) - * here - */ - enum Conclusion { - - /** - * Action required. - */ - ACTION_REQUIRED("action_required"), - - /** - * Cancelled. - */ - CANCELLED("cancelled"), - - /** - * Failure. - */ - FAILURE("failure"), - - /** - * Neutral. - */ - NEUTRAL("neutral"), - - /** - * Success. - */ - SUCCESS("success"), - - /** - * Skipped. - */ - SKIPPED("skipped"), - - /** - * Stale. - */ - STALE("stale"), - - /** - * Timed out. - */ - TIMED_OUT("timed_out"); - - /** - * Conclusion. - */ - private final String conclusion; - - /** - * Ctor. - * @param con Conclusion. - */ - Conclusion(final String con) { - this.conclusion = con; - } - - /** - * Check if check is successful. - * @return True if check is successful. - */ - boolean successful() { - return this == Conclusion.SUCCESS; - } - - /** - * Get conclusion from string. - * @param value String value. - * @return Conclusion. - */ - static Conclusion fromString(final String value) { - return Arrays.stream(Conclusion.values()) - .filter(stat -> stat.same(value)) - .findFirst() - .orElseThrow( - () -> new IllegalArgumentException( - String.format("Invalid value %s for conclusion", value) - ) - ); - } - - /** - * Check if conclusion is the same as value. - * @param value Value to compare. - * @return True if conclusion is the same as value. - */ - boolean same(final String value) { - return this.conclusion.equals(value.toLowerCase(Locale.ROOT)); - } - } } diff --git a/src/main/java/com/jcabi/github/mock/MkCheck.java b/src/main/java/com/jcabi/github/mock/MkCheck.java new file mode 100644 index 000000000..89b6ce6cb --- /dev/null +++ b/src/main/java/com/jcabi/github/mock/MkCheck.java @@ -0,0 +1,119 @@ +/** + * Copyright (c) 2013-2023, jcabi.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: 1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. 2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. 3) Neither the name of the jcabi.com nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jcabi.github.mock; + +import com.jcabi.aspects.Immutable; +import com.jcabi.aspects.Loggable; +import com.jcabi.github.Check; +import com.jcabi.github.Coordinates; +import com.jcabi.github.Pull; +import com.jcabi.xml.XML; +import java.io.IOException; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +/** + * Mock Github check. + * + * @author Volodya Lombrozo (volodya.lombrozo@gmail.com) + * @version $Id$ + * @since 1.6.1 + */ +@Immutable +@Loggable(Loggable.DEBUG) +@ToString +@EqualsAndHashCode(of = {"storage", "coordinates", "pull", "identifier"}) +public final class MkCheck implements Check { + + /** + * Storage. + */ + private final transient MkStorage storage; + + /** + * Coordinates of repo. + */ + private final transient Coordinates coordinates; + + /** + * Pull. + */ + private final transient Pull pull; + + /** + * Check identifier. + */ + private final transient int identifier; + + /** + * Main ctor. + * @param stg Storage + * @param coord Coordinates + * @param pll Pull + * @param number Check identifier + * @checkstyle ParameterNumber (6 lines) + */ + public MkCheck( + final MkStorage stg, + final Coordinates coord, + final Pull pll, + final int number + ) { + this.storage = stg; + this.coordinates = coord; + this.pull = pll; + this.identifier = number; + } + + @Override + public boolean successful() throws IOException { + final XML node = this.storage.xml().nodes(this.xpath()).get(0); + final Status status = Status.fromString( + node.xpath("@status").get(0) + ); + final Conclusion conclusion = Conclusion.fromString( + node.xpath("@conclusion").get(0) + ); + return status == Status.COMPLETED + && conclusion == Conclusion.SUCCESS; + } + + /** + * XPath of this element in XML tree. + * @return XPath + */ + private String xpath() { + return String.format( + // @checkstyle LineLength (1 line) + "/github/repos/repo[@coords='%s']/pulls/pull[number='%d']/checks/check[@id='%d']", + this.coordinates, this.pull.number(), this.identifier + ); + } +} diff --git a/src/main/java/com/jcabi/github/mock/MkChecks.java b/src/main/java/com/jcabi/github/mock/MkChecks.java index ac4eecb09..3da77bd64 100644 --- a/src/main/java/com/jcabi/github/mock/MkChecks.java +++ b/src/main/java/com/jcabi/github/mock/MkChecks.java @@ -29,11 +29,15 @@ */ package com.jcabi.github.mock; +import com.google.common.collect.ImmutableList; import com.jcabi.github.Check; import com.jcabi.github.Checks; +import com.jcabi.github.Coordinates; +import com.jcabi.github.Pull; import java.io.IOException; +import java.security.SecureRandom; import java.util.Collection; -import java.util.Collections; +import org.xembly.Directives; /** * Mock Github Checks. @@ -43,8 +47,91 @@ * @since 1.6.0 */ public final class MkChecks implements Checks { + + /** + * Storage. + */ + private final transient MkStorage storage; + + /** + * Coordinates of repo. + */ + private final transient Coordinates coordinates; + + /** + * Pull. + */ + private final transient Pull pull; + + /** + * Ctor. + * @param strg Storage + * @param coord Coordinates of repo + * @param pll Pull + */ + MkChecks( + final MkStorage strg, + final Coordinates coord, + final Pull pll + ) { + this.storage = strg; + this.coordinates = coord; + this.pull = pll; + } + @Override public Collection all() throws IOException { - return Collections.emptyList(); + return ImmutableList.copyOf( + new MkIterable<>( + this.storage, + String.format("%s/check", this.xpath()), + item -> new MkCheck( + this.storage, + this.coordinates, + this.pull, + Integer.parseInt(item.xpath("@id").get(0)) + ) + ) + ); + } + + /** + * Create check. + * @param status Status. + * @param conclusion Conclusion. + * @return Check. + * @throws IOException If fails. + */ + public Check create( + final Check.Status status, + final Check.Conclusion conclusion + ) throws IOException { + final int identifier = new SecureRandom().nextInt(); + final Directives directives = new Directives() + .xpath(this.xpath()) + .add("check") + .attr("id", identifier) + .attr("status", status.value()) + .attr("conclusion", conclusion.value()) + .up(); + this.storage.apply(directives); + return new MkCheck( + this.storage, + this.coordinates, + this.pull, + identifier + ); + } + + /** + * XPath of this element in XML tree. + * @return XPath + */ + private String xpath() { + return String.format( + // @checkstyle LineLength (1 line) + "/github/repos/repo[@coords='%s']/pulls/pull[number='%d']/checks", + this.coordinates, this.pull.number() + ); } } diff --git a/src/main/java/com/jcabi/github/mock/MkPull.java b/src/main/java/com/jcabi/github/mock/MkPull.java index 447548b49..706ac8182 100644 --- a/src/main/java/com/jcabi/github/mock/MkPull.java +++ b/src/main/java/com/jcabi/github/mock/MkPull.java @@ -220,7 +220,7 @@ public PullComments comments() throws IOException { */ @Override public Checks checks() { - return new MkChecks(); + return new MkChecks(this.storage, this.coords, this); } @Override diff --git a/src/main/java/com/jcabi/github/mock/MkPulls.java b/src/main/java/com/jcabi/github/mock/MkPulls.java index 1346a0e5d..ecb12c926 100644 --- a/src/main/java/com/jcabi/github/mock/MkPulls.java +++ b/src/main/java/com/jcabi/github/mock/MkPulls.java @@ -144,6 +144,7 @@ public Pull create( .add("number").set(Integer.toString(number)).up() .add("head").set(canonical).up() .add("base").set(base).up() + .add("checks").up() .add("user") .add("login").set(this.self) .up() diff --git a/src/test/java/com/jcabi/github/RtCheckTest.java b/src/test/java/com/jcabi/github/RtCheckTest.java index ee0155eea..fa78aad0b 100644 --- a/src/test/java/com/jcabi/github/RtCheckTest.java +++ b/src/test/java/com/jcabi/github/RtCheckTest.java @@ -50,8 +50,8 @@ public final class RtCheckTest { public void checksSuccessfulState() { MatcherAssert.assertThat( new RtCheck( - RtCheck.Status.COMPLETED, - RtCheck.Conclusion.SUCCESS + Check.Status.COMPLETED, + Check.Conclusion.SUCCESS ).successful(), Matchers.is(true) ); @@ -64,8 +64,8 @@ public void checksSuccessfulState() { public void checksNotSuccessfulStateIfInProgress() { MatcherAssert.assertThat( new RtCheck( - RtCheck.Status.IN_PROGRESS, - RtCheck.Conclusion.SUCCESS + Check.Status.IN_PROGRESS, + Check.Conclusion.SUCCESS ).successful(), Matchers.is(false) ); @@ -78,8 +78,8 @@ public void checksNotSuccessfulStateIfInProgress() { public void checksNotSuccessfulState() { MatcherAssert.assertThat( new RtCheck( - RtCheck.Status.COMPLETED, - RtCheck.Conclusion.CANCELLED + Check.Status.COMPLETED, + Check.Conclusion.CANCELLED ).successful(), Matchers.is(false) ); diff --git a/src/test/java/com/jcabi/github/mock/MkCheckTest.java b/src/test/java/com/jcabi/github/mock/MkCheckTest.java new file mode 100644 index 000000000..3062fd15a --- /dev/null +++ b/src/test/java/com/jcabi/github/mock/MkCheckTest.java @@ -0,0 +1,95 @@ +/** + * Copyright (c) 2013-2023, jcabi.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: 1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. 2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. 3) Neither the name of the jcabi.com nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jcabi.github.mock; + +import com.jcabi.github.Check; +import com.jcabi.github.Pull; +import java.io.IOException; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; + +/** + * Test case for {@link MkCheck}. + * + * @author Volodya Lombrozo (volodya.lombrozo@gmail.com) + * @version $Id$ + * @since 1.6.1 + */ +public final class MkCheckTest { + + /** + * Pull request. + */ + private transient Pull pull; + + /** + * Set up. + * @throws java.io.IOException If some problem with I/O. + */ + @Before + public void setUp() throws IOException { + this.pull = new MkGithub() + .randomRepo() + .pulls() + .create("Test PR", "abcdea8", "abcdea9"); + } + + /** + * MkChecks can create successful check. + * @throws IOException If some problem with I/O. + */ + @Test + public void createsSuccessfulCheck() throws IOException { + MatcherAssert.assertThat( + ((MkChecks) this.pull.checks()) + .create(Check.Status.COMPLETED, Check.Conclusion.SUCCESS) + .successful(), + Matchers.is(true) + ); + } + + /** + * MkChecks can create failed check. + * @throws IOException If some problem with I/O. + */ + @Test + public void createsFailedCheck() throws IOException { + MatcherAssert.assertThat( + ((MkChecks) this.pull.checks()) + .create( + Check.Status.COMPLETED, + Check.Conclusion.FAILURE + ).successful(), + Matchers.is(false) + ); + } +} diff --git a/src/test/java/com/jcabi/github/mock/MkChecksTest.java b/src/test/java/com/jcabi/github/mock/MkChecksTest.java new file mode 100644 index 000000000..1a2e03980 --- /dev/null +++ b/src/test/java/com/jcabi/github/mock/MkChecksTest.java @@ -0,0 +1,103 @@ +/** + * Copyright (c) 2013-2023, jcabi.com + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: 1) Redistributions of source code must retain the above + * copyright notice, this list of conditions and the following + * disclaimer. 2) Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. 3) Neither the name of the jcabi.com nor + * the names of its contributors may be used to endorse or promote + * products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package com.jcabi.github.mock; + +import com.jcabi.github.Check; +import com.jcabi.github.Pull; +import java.io.IOException; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Before; +import org.junit.Test; + +/** + * Test case for {@link MkChecks}. + * + * @author Volodya Lombrozo (volodya.lombrozo@gmail.com) + * @version $Id$ + * @since 1.6.1 + */ +public final class MkChecksTest { + + /** + * Pull request. + */ + private transient Pull pull; + + /** + * Set up. + * @throws IOException If some problem with I/O. + */ + @Before + public void setUp() throws IOException { + this.pull = new MkGithub() + .randomRepo() + .pulls() + .create("Test PR", "abcdef8", "abcdef9"); + } + + /** + * MkChecks can return empty checks by default. + * @throws IOException If some problem with I/O. + */ + @Test + public void returnsEmptyChecksByDefault() throws IOException { + MatcherAssert.assertThat( + ((MkChecks) this.pull.checks()).all(), + Matchers.empty() + ); + } + + /** + * MkChecks can create a check. + * @throws IOException If some problem with I/O. + */ + @Test + public void createsCheck() throws IOException { + final MkChecks checks = (MkChecks) this.pull.checks(); + final Check check = checks.create( + Check.Status.COMPLETED, + Check.Conclusion.SUCCESS + ); + MatcherAssert.assertThat( + checks.all(), + Matchers.hasSize(1) + ); + final Check next = checks.all().iterator().next(); + MatcherAssert.assertThat( + check, + Matchers.equalTo(next) + ); + MatcherAssert.assertThat( + next.successful(), + Matchers.is(true) + ); + } +}