package net.pterodactylus.rhynodge.states;
+import java.time.Clock;
+import java.util.Objects;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
* otherwise
*/
protected AbstractState(boolean success) {
- this(success, true, null);
+ this(Clock.systemUTC(), success);
+ }
+
+ /**
+ * Creates a new state.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param success {@code true} if the state is successful, {@code false}
+ * otherwise
+ */
+ protected AbstractState(Clock clock, boolean success) {
+ this(clock, success, true, null);
}
protected AbstractState(boolean success, boolean empty) {
- this(success, empty, null);
+ this(Clock.systemUTC(), success, empty);
+ }
+
+ protected AbstractState(Clock clock, boolean success, boolean empty) {
+ this(clock, success, empty, null);
}
/**
* The exception that occured while retrieving the state
*/
protected AbstractState(Throwable exception) {
- this(false, true, exception);
+ this(Clock.systemUTC(), exception);
+ }
+
+ /**
+ * Creates a new non-successful state with the given exception.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param exception The exception that occured while retrieving the state
+ */
+ protected AbstractState(Clock clock, Throwable exception) {
+ this(clock, false, true, exception);
}
/**
* The exception that occured while retrieving the state
*/
protected AbstractState(boolean success, boolean empty, Throwable exception) {
- this.time = System.currentTimeMillis();
+ this(Clock.systemUTC(), success, empty, exception);
+ }
+
+ /**
+ * Creates a new state.
+ *
+ * @param clock The clock for generating {@link #time}
+ * @param success {@code true} if the state is successful, {@code false}
+ * otherwise
+ * @param exception The exception that occured while retrieving the state
+ */
+ protected AbstractState(Clock clock, boolean success, boolean empty, Throwable exception) {
+ this.time = clock.millis();
this.success = success;
this.empty = empty;
this.exception = exception;
@SuppressWarnings("UnstableApiUsage")
private static final Escaper htmlEscaper = HtmlEscapers.htmlEscaper();
+ @Override
+ public int hashCode() {
+ return Objects.hash(success, empty, time, failCount, exception);
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (!(object instanceof AbstractState)) {
+ return false;
+ }
+ AbstractState abstractState = (AbstractState) object;
+ return (success == abstractState.success) && (empty == abstractState.empty) && (time == abstractState.time) && (failCount == abstractState.failCount) && Objects.equals(exception, abstractState.exception);
+ }
+
}
--- /dev/null
+package net.pterodactylus.rhynodge.states
+
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.junit.Test
+import java.time.Clock
+import java.time.Instant.now
+import java.time.ZoneOffset.UTC
+
+/**
+ * Unit test for [AbstractState].
+ */
+class AbstractStateTest {
+
+ @Test
+ fun `equals returns true when everything is the same`() {
+ val first = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }
+ val second = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }
+ assertThat(first.equals(second), equalTo(true))
+ }
+
+ @Test
+ fun `equals returns false for when success is different`() {
+ val first = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }
+ val second = object : AbstractState(testClock, true) {
+ override fun plainText() = "foo"
+ }
+ assertThat(first.equals(second), equalTo(false))
+ }
+
+ @Test
+ fun `equals return false when empty is different`() {
+ val first = object : AbstractState(testClock, false, false) {
+ override fun plainText() = "foo"
+ }
+ val second = object : AbstractState(testClock, false, true) {
+ override fun plainText() = "foo"
+ }
+ assertThat(first.equals(second), equalTo(false))
+ }
+
+ @Test
+ fun `equals returns false when time is different`() {
+ val first = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }
+ val second = object : AbstractState(Clock.fixed(now().plusSeconds(1), UTC), false) {
+ override fun plainText() = "foo"
+ }
+ assertThat(first.equals(second), equalTo(false))
+ }
+
+ @Test
+ fun `equals returns false when failCount is different`() {
+ val first = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }.apply { setFailCount(12) }
+ val second = object : AbstractState(testClock, false) {
+ override fun plainText() = "foo"
+ }.apply { setFailCount(23) }
+ assertThat(first.equals(second), equalTo(false))
+ }
+
+ @Test
+ fun `equals returns false when exception is different`() {
+ val first = object : AbstractState(testClock, RuntimeException()) {
+ override fun plainText() = "foo"
+ }
+ val second = object : AbstractState(testClock, IllegalArgumentException()) {
+ override fun plainText() = "foo"
+ }
+ assertThat(first.equals(second), equalTo(false))
+ }
+
+}
+
+private val testClock = Clock.fixed(now(), UTC)