From: David ‘Bombe’ Roden Date: Thu, 5 Oct 2017 05:08:58 +0000 (+0200) Subject: Extract test fixtures into their own base class X-Git-Tag: 0.9.7^2~27 X-Git-Url: https://git.pterodactylus.net/?a=commitdiff_plain;h=f339996e95e45359e14becbe62d49863cf26acfd;p=Sone.git Extract test fixtures into their own base class --- diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt index d625fac..9084260 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetNotificationsAjaxPageTest.kt @@ -24,7 +24,7 @@ import java.io.Writer */ class GetNotificationsAjaxPageTest : JsonPageTest("getNotifications.ajax", requiresLogin = false, needsFormPassword = false, pageSupplier = ::GetNotificationsAjaxPage) { - private val notifications = listOf( + private val testNotifications = listOf( createNotification("n1", 2000, "t1", 5000, true), createNotification("n2", 1000, "t2", 6000, false), createNotification("n3", 3000, "t3", 7000, true) @@ -42,9 +42,9 @@ class GetNotificationsAjaxPageTest : JsonPageTest("getNotifications.ajax", requi @Test fun `notification hash is calculated correctly`() { - notifications.forEach { addNotification(it) } + testNotifications.forEach { addNotification(it) } assertThat(json.isSuccess, equalTo(true)) - assertThat(json["notificationHash"].asInt(), equalTo(listOf(1, 0, 2).map(notifications::get).hashCode())) + assertThat(json["notificationHash"].asInt(), equalTo(listOf(1, 0, 2).map(testNotifications::get).hashCode())) } @Test @@ -75,7 +75,7 @@ class GetNotificationsAjaxPageTest : JsonPageTest("getNotifications.ajax", requi @Test fun `notifications are rendered correctly`() { - notifications.forEach { addNotification(it) } + testNotifications.forEach { addNotification(it) } assertThat(json.isSuccess, equalTo(true)) assertThat(json["notifications"].toList().map { node -> listOf("id", "text", "createdTime", "lastUpdatedTime", "dismissable").map { it to node.get(it).asText() }.toMap() }, containsInAnyOrder( mapOf("id" to "n1", "createdTime" to "2000", "lastUpdatedTime" to "5000", "dismissable" to "true", "text" to "t1"), @@ -97,7 +97,7 @@ class GetNotificationsAjaxPageTest : JsonPageTest("getNotifications.ajax", requi whenever(templateContext).thenReturn(TemplateContext()) whenever(render(any(), any())).then { it.get(1).write("t4") } } - notifications.forEach { addNotification(it) } + testNotifications.forEach { addNotification(it) } addNotification(templateNotification) assertThat(json.isSuccess, equalTo(true)) assertThat(json["notifications"].last()["text"].asText(), equalTo("t4")) diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt index af33eea..5bffe09 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetTimesAjaxPageTest.kt @@ -29,8 +29,8 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f private val timeTextConverter = mock() private val l10nFilter = mock() override val page: JsonPage by lazy { GetTimesAjaxPage(webInterface, timeTextConverter, l10nFilter, getTimeZone("UTC")) } - private val posts = listOf(createPost(1), createPost(2)) - private val replies = listOf(createReply(1), createReply(2)) + private val testPosts = listOf(createPost(1), createPost(2)) + private val testReplies = listOf(createReply(1), createReply(2)) private fun createPost(index: Int): Post { return mock().apply { @@ -61,7 +61,7 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f @Test fun `request with single post parameter responds with post times and empty reply times`() { - addPost(posts[0]) + addPost(testPosts[0]) addRequestParameter("posts", "post1") assertThat(json.isSuccess, equalTo(true)) assertThat(json["postTimes"].fields().asSequence().map { it.key to it.value }.toList(), containsInAnyOrder>( @@ -72,7 +72,7 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f @Test fun `request with single reply parameter responds with reply times and empty post times`() { - addReply(replies[0]) + addReply(testReplies[0]) addRequestParameter("replies", "reply1") assertThat(json.isSuccess, equalTo(true)) assertThat(json["postTimes"].toList(), emptyIterable()) @@ -83,8 +83,8 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f @Test fun `request with multiple post parameter responds with post times and empty reply times`() { - addPost(posts[0]) - addPost(posts[1]) + addPost(testPosts[0]) + addPost(testPosts[1]) addRequestParameter("posts", "post1,post2,post3") assertThat(json.isSuccess, equalTo(true)) assertThat(json["postTimes"].fields().asSequence().map { it.key to it.value }.toList(), containsInAnyOrder>( @@ -96,8 +96,8 @@ class GetTimesAjaxPageTest : JsonPageTest("getTimes.ajax", needsFormPassword = f @Test fun `request with multiple reply parameters responds with reply times and empty post times`() { - addReply(replies[0]) - addReply(replies[1]) + addReply(testReplies[0]) + addReply(testReplies[1]) addRequestParameter("replies", "reply1,reply2,reply3") assertThat(json.isSuccess, equalTo(true)) assertThat(json["postTimes"].toList(), emptyIterable()) diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt index 73dba5a..558b414 100644 --- a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt @@ -1,46 +1,10 @@ package net.pterodactylus.sone.web.ajax -import com.google.common.eventbus.EventBus -import freenet.clients.http.ToadletContext -import freenet.l10n.BaseL10n -import freenet.support.SimpleReadOnlyArrayBucket -import freenet.support.api.HTTPRequest -import net.pterodactylus.sone.core.Core -import net.pterodactylus.sone.core.ElementLoader -import net.pterodactylus.sone.core.LinkedElement -import net.pterodactylus.sone.core.Preferences -import net.pterodactylus.sone.core.UpdateChecker -import net.pterodactylus.sone.data.Album -import net.pterodactylus.sone.data.Image -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Profile -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.data.Sone.SoneStatus -import net.pterodactylus.sone.data.Sone.SoneStatus.idle -import net.pterodactylus.sone.data.SoneOptions.DefaultSoneOptions -import net.pterodactylus.sone.test.deepMock -import net.pterodactylus.sone.test.get import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import net.pterodactylus.sone.utils.asOptional import net.pterodactylus.sone.web.WebInterface -import net.pterodactylus.sone.web.page.FreenetRequest -import net.pterodactylus.util.notify.Notification -import net.pterodactylus.util.template.TemplateContextFactory -import net.pterodactylus.util.web.Method.GET import org.hamcrest.MatcherAssert.assertThat import org.hamcrest.Matchers.equalTo -import org.junit.Before import org.junit.Test -import org.mockito.ArgumentMatchers.any -import org.mockito.ArgumentMatchers.anyBoolean -import org.mockito.ArgumentMatchers.anyInt -import org.mockito.ArgumentMatchers.anyString -import org.mockito.ArgumentMatchers.eq -import org.mockito.ArgumentMatchers.isNull -import java.util.NoSuchElementException -import javax.naming.SizeLimitExceededException /** * Base class for tests for any [JsonPage] implementations. @@ -49,211 +13,15 @@ abstract class JsonPageTest( private val expectedPath: String, private val requiresLogin: Boolean = true, private val needsFormPassword: Boolean = true, - pageSupplier: (WebInterface) -> JsonPage = { _ -> mock() }) { + pageSupplier: (WebInterface) -> JsonPage = { mock() }): TestObjects() { - protected val webInterface = mock() - protected val l10n = mock() - protected val core = mock() - protected val eventBus = mock() - protected val preferences = Preferences(eventBus) - protected val updateChecker = mock() - protected val elementLoader = mock() protected open val page: JsonPage by lazy { pageSupplier(webInterface) } - protected val json by lazy { page.createJsonObject(freenetRequest) } - - protected val toadletContext = mock() - protected val freenetRequest = mock() - protected val httpRequest = mock() - protected val currentSone = deepMock() - protected val profile = Profile(currentSone) - - private val requestHeaders = mutableMapOf() - private val requestParameters = mutableMapOf() - private val requestParts = mutableMapOf() - private val localSones = mutableMapOf() - private val remoteSones = mutableMapOf() - private val posts = mutableMapOf() - private val postLikes = mutableMapOf>() - private val newPosts = mutableMapOf() - private val replies = mutableMapOf() - private val replyLikes = mutableMapOf>() - private val newReplies = mutableMapOf() - private val linkedElements = mutableMapOf() - private val notifications = mutableMapOf() - private val albums = mutableMapOf() - private val images = mutableMapOf() - private val translations = mutableMapOf() - - @Before - fun setupWebInterface() { - whenever(webInterface.templateContextFactory).thenReturn(TemplateContextFactory()) - whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(currentSone) - whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone) - whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone) - whenever(webInterface.core).thenReturn(core) - whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications.values } - whenever(webInterface.getNotification(anyString())).then { notifications[it[0]].asOptional() } - whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values } - whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values } - whenever(webInterface.l10n).thenReturn(l10n) - } - - @Before - fun setupTranslations() { - whenever(l10n.getString(anyString())).then { translations[it[0]] } - } - - @Before - fun setupCore() { - whenever(core.preferences).thenReturn(preferences) - whenever(core.updateChecker).thenReturn(updateChecker) - whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() } - whenever(core.getLocalSone(anyString())).thenAnswer { localSones[it[0]] } - whenever(core.getPost(anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() } - whenever(core.getLikes(any())).then { postLikes[it[0]] ?: emptySet() } - whenever(core.getLikes(any())).then { replyLikes[it[0]] ?: emptySet() } - whenever(core.getPostReply(anyString())).then { replies[it[0]].asOptional() } - whenever(core.getAlbum(anyString())).then { albums[it[0]] } - whenever(core.getImage(anyString())).then { images[it[0]] } - whenever(core.getImage(anyString(), anyBoolean())).then { images[it[0]] } - } - - @Before - fun setupElementLoader() { - whenever(elementLoader.loadElement(anyString())).thenAnswer { - linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true) - } - } - - @Before - fun setupCurrentSone() { - whenever(currentSone.options).thenReturn(DefaultSoneOptions()) - currentSone.mock("soneId", "Sone_Id", true, 1000, idle) - } - - @Before - fun setupFreenetRequest() { - whenever(freenetRequest.toadletContext).thenReturn(toadletContext) - whenever(freenetRequest.method).thenReturn(GET) - whenever(freenetRequest.httpRequest).thenReturn(httpRequest) - } - - @Before - fun setupHttpRequest() { - whenever(httpRequest.method).thenReturn("GET") - whenever(httpRequest.getHeader(anyString())).thenAnswer { requestHeaders[it.get(0).toLowerCase()] } - whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" } - whenever(httpRequest.getParam(anyString(), anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) } - whenever(httpRequest.getParam(anyString(), isNull())).thenAnswer { requestParameters[it.getArgument(0)] } - whenever(httpRequest.getPart(anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } } - whenever(httpRequest.getPartAsBytesFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) } - whenever(httpRequest.getPartAsBytesThrowing(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { it.toByteArray().let { if (it.size > invocation.getArgument(1)) throw SizeLimitExceededException() else it } } ?: throw NoSuchElementException() } - whenever(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" } - whenever(httpRequest.getPartAsStringThrowing(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { if (it.length > invocation.getArgument(1)) throw SizeLimitExceededException() else it } ?: throw NoSuchElementException() } - whenever(httpRequest.getIntPart(anyString(), anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) } - whenever(httpRequest.isPartSet(anyString())).thenAnswer { it.getArgument(0) in requestParts } - } - - @Before - fun setupProfile() { - whenever(currentSone.profile).thenReturn(profile) + protected val json by lazy { + page.createJsonObject(freenetRequest) } protected val JsonReturnObject.error get() = if (this is JsonErrorReturnObject) this.error else null - protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply { - whenever(this.id).thenReturn(id) - whenever(this.name).thenReturn(name) - whenever(isLocal).thenReturn(local) - whenever(this.time).thenReturn(time) - whenever(this.status).thenReturn(status) - } - - protected fun unsetCurrentSone() { - whenever(webInterface.getCurrentSone(eq(toadletContext), anyBoolean())).thenReturn(null) - whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null) - whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null) - } - - protected fun addRequestHeader(key: String, value: String) { - requestHeaders += key.toLowerCase() to value - } - - protected fun addRequestParameter(key: String, value: String) { - requestParameters += key to value - } - - protected fun addRequestPart(key: String, value: String) { - requestParts += key to value - } - - protected fun addNotification(notification: Notification, notificationId: String? = null) { - notifications[notificationId ?: notification.id] = notification - } - - protected fun addSone(sone: Sone, soneId: String? = null) { - remoteSones += (soneId ?: sone.id) to sone - } - - protected fun addLocalSone(sone: Sone, id: String? = null) { - localSones[id ?: sone.id] = sone - } - - protected fun addPost(post: Post, id: String? = null) { - posts[id ?: post.id] = post - } - - protected fun addLikes(post: Post, vararg sones: Sone) { - postLikes[post] = setOf(*sones) - } - - protected fun addLikes(reply: PostReply, vararg sones: Sone) { - replyLikes[reply] = setOf(*sones) - } - - protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) = - mock().apply { - whenever(this.id).thenReturn(id) - val sone = mock().apply { whenever(this.id).thenReturn(soneId) } - whenever(this.sone).thenReturn(sone) - whenever(this.time).thenReturn(time) - whenever(this.recipientId).thenReturn(recipientId.asOptional()) - }.also { newPosts[id] = it } - - protected fun addReply(reply: PostReply, id: String? = null) { - replies[id ?: reply.id] = reply - } - - protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) { - newReplies[id] = mock().apply { - whenever(this.id).thenReturn(id) - val sone = mock().apply { whenever(this.id).thenReturn(soneId) } - whenever(this.sone).thenReturn(sone) - val postSone = mock().apply { whenever(this.id).thenReturn(postSoneId) } - val post = mock().apply { - whenever(this.sone).thenReturn(postSone) - } - whenever(this.post).thenReturn(post.asOptional()) - whenever(this.postId).thenReturn(postId) - } - } - - protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) { - linkedElements[link] = LinkedElement(link, failed, loading) - } - - protected fun addAlbum(album: Album, albumId: String? = null) { - albums[albumId ?: album.id] = album - } - - protected fun addImage(image: Image, imageId: String? = null) { - images[imageId ?: image.id] = image - } - - protected fun addTranslation(key: String, value: String) { - translations[key] = value - } - @Test fun `page returns correct path`() { assertThat(page.path, equalTo(expectedPath)) diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt new file mode 100644 index 0000000..a7e0a8a --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/TestObjects.kt @@ -0,0 +1,226 @@ +package net.pterodactylus.sone.web.ajax + +import com.google.common.eventbus.EventBus +import freenet.clients.http.ToadletContext +import freenet.l10n.BaseL10n +import freenet.support.SimpleReadOnlyArrayBucket +import freenet.support.api.HTTPRequest +import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.core.ElementLoader +import net.pterodactylus.sone.core.LinkedElement +import net.pterodactylus.sone.core.Preferences +import net.pterodactylus.sone.core.UpdateChecker +import net.pterodactylus.sone.data.Album +import net.pterodactylus.sone.data.Image +import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.data.PostReply +import net.pterodactylus.sone.data.Profile +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.Sone.SoneStatus +import net.pterodactylus.sone.data.Sone.SoneStatus.idle +import net.pterodactylus.sone.data.SoneOptions.DefaultSoneOptions +import net.pterodactylus.sone.test.deepMock +import net.pterodactylus.sone.test.get +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.utils.asOptional +import net.pterodactylus.sone.web.WebInterface +import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.util.notify.Notification +import net.pterodactylus.util.template.TemplateContextFactory +import net.pterodactylus.util.web.Method.GET +import net.pterodactylus.util.web.Method.POST +import org.mockito.ArgumentMatchers +import java.util.NoSuchElementException +import javax.naming.SizeLimitExceededException + +/** + * Base class for tests that supplies commonly used objects. + */ +open class TestObjects { + + val webInterface = mock() + var formPassword = "form-password" + val l10n = mock() + val core = mock() + val eventBus = mock() + val preferences = Preferences(eventBus) + val updateChecker = mock() + val elementLoader = mock() + + val toadletContext = mock() + val freenetRequest = mock() + val httpRequest = mock() + val currentSone = deepMock() + val profile = Profile(currentSone) + + val requestHeaders = mutableMapOf() + val requestParameters = mutableMapOf() + val requestParts = mutableMapOf() + val localSones = mutableMapOf() + val remoteSones = mutableMapOf() + val posts = mutableMapOf() + val postLikes = mutableMapOf>() + val newPosts = mutableMapOf() + val replies = mutableMapOf() + val replyLikes = mutableMapOf>() + val newReplies = mutableMapOf() + val linkedElements = mutableMapOf() + val notifications = mutableMapOf() + val albums = mutableMapOf() + val images = mutableMapOf() + val translations = mutableMapOf() + + init { + whenever(webInterface.templateContextFactory).thenReturn(TemplateContextFactory()) + whenever(webInterface.getCurrentSone(ArgumentMatchers.eq(toadletContext), ArgumentMatchers.anyBoolean())).thenReturn(currentSone) + whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone) + whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone) + whenever(webInterface.core).thenReturn(core) + whenever(webInterface.formPassword).then { formPassword } + whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications.values } + whenever(webInterface.getNotification(ArgumentMatchers.anyString())).then { notifications[it[0]].asOptional() } + whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values } + whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values } + whenever(webInterface.l10n).thenReturn(l10n) + + whenever(l10n.getString(ArgumentMatchers.anyString())).then { translations[it[0]] } + + whenever(core.preferences).thenReturn(preferences) + whenever(core.updateChecker).thenReturn(updateChecker) + whenever(core.getSone(ArgumentMatchers.anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() } + whenever(core.getLocalSone(ArgumentMatchers.anyString())).thenAnswer { localSones[it[0]] } + whenever(core.getPost(ArgumentMatchers.anyString())).thenAnswer { (posts + newPosts)[it[0]].asOptional() } + whenever(core.getLikes(ArgumentMatchers.any())).then { postLikes[it[0]] ?: emptySet() } + whenever(core.getLikes(ArgumentMatchers.any())).then { replyLikes[it[0]] ?: emptySet() } + whenever(core.getPostReply(ArgumentMatchers.anyString())).then { replies[it[0]].asOptional() } + whenever(core.getAlbum(ArgumentMatchers.anyString())).then { albums[it[0]] } + whenever(core.getImage(ArgumentMatchers.anyString())).then { images[it[0]] } + whenever(core.getImage(ArgumentMatchers.anyString(), ArgumentMatchers.anyBoolean())).then { images[it[0]] } + + whenever(elementLoader.loadElement(ArgumentMatchers.anyString())).thenAnswer { + linkedElements[it.getArgument(0)] ?: LinkedElement(it.getArgument(0), loading = true) + } + + whenever(currentSone.options).thenReturn(DefaultSoneOptions()) + currentSone.mock("soneId", "Sone_Id", true, 1000, idle) + + whenever(freenetRequest.toadletContext).thenReturn(toadletContext) + whenever(freenetRequest.method).thenReturn(GET) + whenever(freenetRequest.httpRequest).thenReturn(httpRequest) + + whenever(httpRequest.method).thenReturn("GET") + whenever(httpRequest.getHeader(ArgumentMatchers.anyString())).thenAnswer { requestHeaders[it.get(0).toLowerCase()] } + whenever(httpRequest.getParam(ArgumentMatchers.anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" } + whenever(httpRequest.getParam(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: it.getArgument(1) } + whenever(httpRequest.getParam(ArgumentMatchers.anyString(), ArgumentMatchers.isNull())).thenAnswer { requestParameters[it.getArgument(0)] } + whenever(httpRequest.getPart(ArgumentMatchers.anyString())).thenAnswer { requestParts[it.getArgument(0)]?.let { SimpleReadOnlyArrayBucket(it.toByteArray()) } } + whenever(httpRequest.getPartAsBytesFailsafe(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.toByteArray()?.copyOf(it.getArgument(1)) ?: ByteArray(0) } + whenever(httpRequest.getPartAsBytesThrowing(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { it.toByteArray().let { if (it.size > invocation.getArgument(1)) throw SizeLimitExceededException() else it } } ?: throw NoSuchElementException() } + whenever(httpRequest.getPartAsStringFailsafe(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())).thenAnswer { requestParts[it.getArgument(0)]?.substring(0, it.getArgument(1)) ?: "" } + whenever(httpRequest.getPartAsStringThrowing(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.let { if (it.length > invocation.getArgument(1)) throw SizeLimitExceededException() else it } ?: throw NoSuchElementException() } + whenever(httpRequest.getIntPart(ArgumentMatchers.anyString(), ArgumentMatchers.anyInt())).thenAnswer { invocation -> requestParts[invocation.getArgument(0)]?.toIntOrNull() ?: invocation.getArgument(1) } + whenever(httpRequest.isPartSet(ArgumentMatchers.anyString())).thenAnswer { it.getArgument(0) in requestParts } + + whenever(currentSone.profile).thenReturn(profile) + } + + protected fun Sone.mock(id: String, name: String, local: Boolean = false, time: Long, status: SoneStatus = idle) = apply { + whenever(this.id).thenReturn(id) + whenever(this.name).thenReturn(name) + whenever(isLocal).thenReturn(local) + whenever(this.time).thenReturn(time) + whenever(this.status).thenReturn(status) + } + + protected fun unsetCurrentSone() { + whenever(webInterface.getCurrentSone(ArgumentMatchers.eq(toadletContext), ArgumentMatchers.anyBoolean())).thenReturn(null) + whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null) + whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null) + } + + protected fun postRequest() { + whenever(freenetRequest.method).thenReturn(POST) + whenever(httpRequest.method).thenReturn("POST") + } + + protected fun addRequestHeader(key: String, value: String) { + requestHeaders += key.toLowerCase() to value + } + + protected fun addRequestParameter(key: String, value: String) { + requestParameters += key to value + } + + protected fun addRequestPart(key: String, value: String) { + requestParts += key to value + } + + protected fun addNotification(notification: Notification, notificationId: String? = null) { + notifications[notificationId ?: notification.id] = notification + } + + protected fun addSone(sone: Sone, soneId: String? = null) { + remoteSones += (soneId ?: sone.id) to sone + } + + protected fun addLocalSone(sone: Sone, id: String? = null) { + localSones[id ?: sone.id] = sone + } + + protected fun addPost(post: Post, id: String? = null) { + posts[id ?: post.id] = post + } + + protected fun addLikes(post: Post, vararg sones: Sone) { + postLikes[post] = setOf(*sones) + } + + protected fun addLikes(reply: PostReply, vararg sones: Sone) { + replyLikes[reply] = setOf(*sones) + } + + protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) = + mock().apply { + whenever(this.id).thenReturn(id) + val sone = mock().apply { whenever(this.id).thenReturn(soneId) } + whenever(this.sone).thenReturn(sone) + whenever(this.time).thenReturn(time) + whenever(this.recipientId).thenReturn(recipientId.asOptional()) + }.also { newPosts[id] = it } + + protected fun addReply(reply: PostReply, id: String? = null) { + replies[id ?: reply.id] = reply + } + + protected fun addNewReply(id: String, soneId: String, postId: String, postSoneId: String) { + newReplies[id] = mock().apply { + whenever(this.id).thenReturn(id) + val sone = mock().apply { whenever(this.id).thenReturn(soneId) } + whenever(this.sone).thenReturn(sone) + val postSone = mock().apply { whenever(this.id).thenReturn(postSoneId) } + val post = mock().apply { + whenever(this.sone).thenReturn(postSone) + } + whenever(this.post).thenReturn(post.asOptional()) + whenever(this.postId).thenReturn(postId) + } + } + + protected fun addLinkedElement(link: String, loading: Boolean, failed: Boolean) { + linkedElements[link] = LinkedElement(link, failed, loading) + } + + protected fun addAlbum(album: Album, albumId: String? = null) { + albums[albumId ?: album.id] = album + } + + protected fun addImage(image: Image, imageId: String? = null) { + images[imageId ?: image.id] = image + } + + protected fun addTranslation(key: String, value: String) { + translations[key] = value + } + +}