Add fallback query
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 18 Oct 2016 20:08:13 +0000 (22:08 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Tue, 18 Oct 2016 20:08:13 +0000 (22:08 +0200)
src/main/java/net/pterodactylus/rhynodge/queries/FallbackQuery.kt [new file with mode: 0644]
src/test/kotlin/net/pterodactylus/rhynodge/queries/FallbackQueryTest.kt [new file with mode: 0644]

diff --git a/src/main/java/net/pterodactylus/rhynodge/queries/FallbackQuery.kt b/src/main/java/net/pterodactylus/rhynodge/queries/FallbackQuery.kt
new file mode 100644 (file)
index 0000000..6e5fbd1
--- /dev/null
@@ -0,0 +1,26 @@
+package net.pterodactylus.rhynodge.queries
+
+import net.pterodactylus.rhynodge.Query
+import net.pterodactylus.rhynodge.State
+import net.pterodactylus.rhynodge.states.FailedState
+
+/**
+ * [Query] that can run a number of other [Query]s, returning the first successful [State] that is encountered.
+ *
+ * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net)
+ */
+class FallbackQuery(private vararg val queries: Query) : Query {
+
+       init {
+               if (queries.isEmpty()) {
+                       throw IllegalArgumentException("queries must not be empty")
+               }
+       }
+
+       override fun state(): State {
+               var lastFailedState: State = FailedState()
+               queries.asSequence().map(Query::state).forEach { lastFailedState = it; if (it.success()) return it }
+               return lastFailedState
+       }
+
+}
diff --git a/src/test/kotlin/net/pterodactylus/rhynodge/queries/FallbackQueryTest.kt b/src/test/kotlin/net/pterodactylus/rhynodge/queries/FallbackQueryTest.kt
new file mode 100644 (file)
index 0000000..209454d
--- /dev/null
@@ -0,0 +1,101 @@
+package net.pterodactylus.rhynodge.queries
+
+import net.pterodactylus.rhynodge.Query
+import net.pterodactylus.rhynodge.State
+import net.pterodactylus.rhynodge.states.AbstractState
+import net.pterodactylus.rhynodge.states.FailedState
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.`is`
+import org.hamcrest.Matchers.sameInstance
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.ExpectedException
+import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.never
+import org.mockito.Mockito.verify
+
+/**
+ * Unit test for [FallbackQuery].
+ *
+ * @author [David ‘Bombe’ Roden](mailto:bombe@pterodactylus.net)
+ */
+class FallbackQueryTest {
+
+       @JvmField @Rule val expectedException = ExpectedException.none()!!
+
+       private val firstQuery = mock(Query::class.java)
+       private val secondQuery = mock(Query::class.java)
+       private val thirdQuery = mock(Query::class.java)
+       private val query = FallbackQuery(firstQuery, secondQuery, thirdQuery)
+
+       private fun setupQueries(firstState: State = FailedState(), secondState: State = FailedState(), thirdState: State = FailedState()) {
+               `when`(firstQuery.state()).thenReturn(firstState)
+               `when`(secondQuery.state()).thenReturn(secondState)
+               `when`(thirdQuery.state()).thenReturn(thirdState)
+       }
+
+       @Test
+       fun `fallback query returns state of third query`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(thirdState = successState)
+               assertThat(query.state(), sameInstance<State>(successState))
+       }
+
+       @Test
+       fun `fallback query calls all three queries`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(thirdState = successState)
+               query.state()
+               verify(firstQuery).state()
+               verify(secondQuery).state()
+               verify(thirdQuery).state()
+       }
+
+       @Test
+       fun `fallback query returns second state`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(secondState = successState)
+               assertThat(query.state(), sameInstance<State>(successState))
+       }
+
+       @Test
+       fun `fallback query does not query third query`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(secondState = successState)
+               query.state()
+               verify(firstQuery).state()
+               verify(secondQuery).state()
+               verify(thirdQuery, never()).state()
+       }
+
+       @Test
+       fun `fallback query returns first state`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(firstState = successState)
+               assertThat(query.state(), sameInstance<State>(successState))
+       }
+
+       @Test
+       fun `fallback query does not query second and third query`() {
+               val successState: AbstractState = object : AbstractState() {}
+               setupQueries(firstState = successState)
+               query.state()
+               verify(firstQuery).state()
+               verify(secondQuery, never()).state()
+               verify(thirdQuery, never()).state()
+       }
+
+       @Test
+       fun `fallback query returns failed state if no query succeeds`() {
+               setupQueries()
+               assertThat(query.state().success(), `is`(false))
+       }
+
+       @Test
+       fun `fallback query can not be created without queries`() {
+               expectedException.expect(IllegalArgumentException::class.java)
+               FallbackQuery()
+       }
+
+}