From 14bcfdd073d7ae75ae77bc112e38b29aee243411 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sat, 1 Apr 2017 09:48:50 +0200 Subject: [PATCH] Add unit test for get status AJAX page --- .../sone/web/ajax/GetStatusAjaxPage.java | 2 +- .../sone/web/ajax/GetStatusAjaxPageTest.kt | 139 +++++++++++++++++++++ .../pterodactylus/sone/web/ajax/JsonPageTest.kt | 123 ++++++++++++++++++ 3 files changed, 263 insertions(+), 1 deletion(-) create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt diff --git a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java index efb6716..8e0ac1e 100644 --- a/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java +++ b/src/main/java/net/pterodactylus/sone/web/ajax/GetStatusAjaxPage.java @@ -153,7 +153,7 @@ public class GetStatusAjaxPage extends JsonPage { ObjectNode jsonSone = new ObjectNode(instance); jsonSone.put("id", sone.getId()); jsonSone.put("name", SoneAccessor.getNiceName(sone)); - jsonSone.put("local", sone.getInsertUri() != null); + jsonSone.put("local", sone.isLocal()); jsonSone.put("status", sone.getStatus().name()); jsonSone.put("modified", webInterface.getCore().isModifiedSone(sone)); jsonSone.put("locked", webInterface.getCore().isLocked(sone)); diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt new file mode 100644 index 0000000..d397b93 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/GetStatusAjaxPageTest.kt @@ -0,0 +1,139 @@ +package net.pterodactylus.sone.web.ajax + +import com.fasterxml.jackson.databind.JsonNode +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.data.Sone.SoneStatus.downloading +import net.pterodactylus.sone.data.Sone.SoneStatus.inserting +import net.pterodactylus.sone.freenet.L10nFilter +import net.pterodactylus.sone.freenet.L10nText +import net.pterodactylus.sone.test.deepMock +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.text.TimeText +import net.pterodactylus.sone.text.TimeTextConverter +import net.pterodactylus.util.notify.Notification +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.allOf +import org.hamcrest.Matchers.containsInAnyOrder +import org.hamcrest.Matchers.emptyIterable +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.hasEntry +import org.junit.Before +import org.junit.Test +import org.mockito.ArgumentMatchers.any +import org.mockito.ArgumentMatchers.anyLong + +/** + * Unit test for [GetStatusAjaxPage]. + */ +class GetStatusAjaxPageTest: JsonPageTest() { + + private val timeTextConverter = mock() + private val l10nFilter = mock() + override var page: JsonPage = GetStatusAjaxPage(webInterface, timeTextConverter, l10nFilter) + + @Before + fun setupTimeTextConverter() { + whenever(timeTextConverter.getTimeText(anyLong())).thenAnswer { TimeText(L10nText(it.getArgument(0).toString()), it.getArgument(0)) } + whenever(l10nFilter.format(any(), any(), any())).thenAnswer { it.getArgument(1).text } + } + + @Test + fun `page returns correct path`() { + assertThat(page.path, equalTo("getStatus.ajax")) + } + + @Test + fun `page does not require form password`() { + assertThat(page.needsFormPassword(), equalTo(false)) + } + + @Test + fun `page does not require login`() { + assertThat(page.requiresLogin(), equalTo(false)) + } + + @Test + fun `page returns correct attribute “loggedIn” if sone is logged in`() { + assertThat(json.get("loggedIn").asText(), equalTo("true")) + } + + @Test + fun `page returns correct attribute “loggedIn” if sone is not logged in`() { + unsetCurrentSone() + assertThat(json.get("loggedIn").asText(), equalTo("false")) + } + + @Test + fun `page returns options for sone if sone is logged in`() { + assertThat(json.get("options").toMap(), allOf( + hasEntry("ShowNotification/NewSones", "false"), + hasEntry("ShowNotification/NewPosts", "false"), + hasEntry("ShowNotification/NewReplies", "false") + )) + } + + @Test + fun `page returns empty options if sone is not logged in`() { + unsetCurrentSone() + assertThat(json.get("options"), emptyIterable()) + } + + @Test + fun `page returns empty sones object if no sone is logged in and no sones parameter is given`() { + unsetCurrentSone() + assertThat(json.get("sones"), emptyIterable()) + } + + @Test + fun `page returns a sones object with the current sone if not other sones parameter is given`() { + assertThat(json.get("sones").elements().asSequence().map { it.toMap() }.toList(), containsInAnyOrder( + mapOf("id" to "soneId", "name" to "Sone_Id", "local" to "true", "status" to "idle", "modified" to "false", "locked" to "false", "lastUpdatedUnknown" to "false", "lastUpdated" to "Jan 1, 1970, 01:00:01", "lastUpdatedText" to "1000") + )) + } + + @Test + fun `page returns some sones objects with the current sone and some sones given as sones parameter`() { + addSone(deepMock().mock("sone1", "Sone 1", false, 2000, downloading)) + addSone(deepMock().mock("sone3", "Sone 3", true, 3000, inserting)) + addRequestParameter("soneIds", "sone1,sone2,sone3") + assertThat(json.get("sones").elements().asSequence().map { it.toMap() }.toList(), containsInAnyOrder( + mapOf("id" to "soneId", "name" to "Sone_Id", "local" to "true", "status" to "idle", "modified" to "false", "locked" to "false", "lastUpdatedUnknown" to "false", "lastUpdated" to "Jan 1, 1970, 01:00:01", "lastUpdatedText" to "1000"), + mapOf("id" to "sone1", "name" to "Sone 1", "local" to "false", "status" to "downloading", "modified" to "false", "locked" to "false", "lastUpdatedUnknown" to "false", "lastUpdated" to "Jan 1, 1970, 01:00:02", "lastUpdatedText" to "2000"), + mapOf("id" to "sone3", "name" to "Sone 3", "local" to "true", "status" to "inserting", "modified" to "false", "locked" to "false", "lastUpdatedUnknown" to "false", "lastUpdated" to "Jan 1, 1970, 01:00:03", "lastUpdatedText" to "3000") + )) + } + + @Test + fun `page returns correct notifications hash`() { + val notifications = listOf( + mock().apply { whenever(this.createdTime).thenReturn(2000) }, + mock().apply { whenever(this.createdTime).thenReturn(1000) } + ) + addNotification(*notifications.toTypedArray()) + assertThat(json.get("notificationHash").asInt(), equalTo(notifications.sortedBy { it.createdTime }.hashCode())) + } + + @Test + fun `page returns new posts`() { + addNewPost("post1", "sone1", 1000) + addNewPost("post2", "sone2", 2000, "sone1") + assertThat(json.get("newPosts").elements().asSequence().map { it.toMap() }.toList(), containsInAnyOrder( + mapOf("id" to "post1", "sone" to "sone1", "time" to "1000", "recipient" to null), + mapOf("id" to "post2", "sone" to "sone2", "time" to "2000", "recipient" to "sone1") + )) + } + + @Test + fun `page returns new replies`() { + addNewReply("reply1", "sone1", "post1", "sone11") + addNewReply("reply2", "sone2", "post2", "sone22") + assertThat(json.get("newReplies").elements().asSequence().map { it.toMap() }.toList(), containsInAnyOrder( + mapOf("id" to "reply1", "sone" to "sone1", "post" to "post1", "postSone" to "sone11"), + mapOf("id" to "reply2", "sone" to "sone2", "post" to "post2", "postSone" to "sone22") + )) + } + + private fun JsonNode.toMap() = fields().asSequence().map { it.key!! to if (it.value.isNull) null else it.value.asText()!! }.toMap() + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt new file mode 100644 index 0000000..84f74f9 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/ajax/JsonPageTest.kt @@ -0,0 +1,123 @@ +package net.pterodactylus.sone.web.ajax + +import freenet.clients.http.ToadletContext +import freenet.support.api.HTTPRequest +import net.pterodactylus.sone.core.Core +import net.pterodactylus.sone.data.Post +import net.pterodactylus.sone.data.PostReply +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.test.asOptional +import net.pterodactylus.sone.test.deepMock +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.sone.web.WebInterface +import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.util.notify.Notification +import org.junit.Before +import org.mockito.ArgumentMatchers.anyString + +/** + * Base class for tests for any [JsonPage] implementations. + */ +open class JsonPageTest { + + protected val webInterface = mock() + protected val core = mock() + protected open lateinit var page: JsonPage + protected val json by lazy { page.createJsonObject(freenetRequest)!! } + + protected val toadletContext = mock() + protected val freenetRequest = mock() + protected val httpRequest = mock() + protected val currentSone = deepMock() + + private val requestParameters = mutableMapOf() + private val localSones = mutableMapOf() + private val remoteSones = mutableMapOf() + private val newPosts = mutableMapOf() + private val newReplies = mutableMapOf() + private val notifications = mutableListOf() + + @Before + fun setupWebInterface() { + whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(currentSone) + whenever(webInterface.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(currentSone) + whenever(webInterface.core).thenReturn(core) + whenever(webInterface.getNotifications(currentSone)).thenAnswer { notifications } + whenever(webInterface.getNewPosts(currentSone)).thenAnswer { newPosts.values } + whenever(webInterface.getNewReplies(currentSone)).thenAnswer { newReplies.values } + } + + @Before + fun setupCore() { + whenever(core.getSone(anyString())).thenAnswer { (localSones + remoteSones)[it.getArgument(0)].asOptional() } + } + + @Before + fun setupCurrentSone() { + currentSone.mock("soneId", "Sone_Id", true, 1000, idle) + } + + @Before + fun setupFreenetRequest() { + whenever(freenetRequest.toadletContext).thenReturn(toadletContext) + whenever(freenetRequest.httpRequest).thenReturn(httpRequest) + } + + @Before + fun setupHttpRequest() { + whenever(httpRequest.getParam(anyString())).thenAnswer { requestParameters[it.getArgument(0)] ?: "" } + } + + 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.getCurrentSoneWithoutCreatingSession(toadletContext)).thenReturn(null) + whenever(webInterface.getCurrentSoneCreatingSession(toadletContext)).thenReturn(null) + } + + protected fun addRequestParameter(key: String, value: String) { + requestParameters += key to value + } + + protected fun addNotification(vararg notifications: Notification) { + this.notifications += notifications + } + + protected fun addSone(sone: Sone) { + remoteSones += sone.id to sone + } + + protected fun addNewPost(id: String, soneId: String, time: Long, recipientId: String? = null) { + newPosts[id] = 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()) + } + } + + 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) + } + } + +} -- 2.7.4