From d327ccf1eeca1bd9544c523e98a6d1dc551c0015 Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Tue, 14 Feb 2017 18:25:57 +0100 Subject: [PATCH] Replace create sone page and test with Kotlin version --- .../net/pterodactylus/sone/web/CreateSonePage.java | 142 ------------------ .../net/pterodactylus/sone/web/CreateSonePage.kt | 44 ++++++ .../pterodactylus/sone/web/CreateSonePageTest.java | 167 --------------------- .../pterodactylus/sone/web/CreateSonePageTest.kt | 148 ++++++++++++++++++ 4 files changed, 192 insertions(+), 309 deletions(-) delete mode 100644 src/main/java/net/pterodactylus/sone/web/CreateSonePage.java create mode 100644 src/main/kotlin/net/pterodactylus/sone/web/CreateSonePage.kt delete mode 100644 src/test/java/net/pterodactylus/sone/web/CreateSonePageTest.java create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/CreateSonePageTest.kt diff --git a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java b/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java deleted file mode 100644 index 2484e3a..0000000 --- a/src/main/java/net/pterodactylus/sone/web/CreateSonePage.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Sone - CreateSonePage.java - Copyright © 2010–2016 David Roden - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package net.pterodactylus.sone.web; - -import static java.util.logging.Logger.getLogger; - -import java.util.ArrayList; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; -import java.util.Set; -import java.util.logging.Level; -import java.util.logging.Logger; - -import net.pterodactylus.sone.core.Core; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.freenet.wot.OwnIdentity; -import net.pterodactylus.sone.web.page.FreenetRequest; -import net.pterodactylus.util.template.Template; -import net.pterodactylus.util.template.TemplateContext; -import net.pterodactylus.util.web.Method; -import freenet.clients.http.ToadletContext; - -/** - * The “create Sone” page lets the user create a new Sone. - * - * @author David ‘Bombe’ Roden - */ -public class CreateSonePage extends SoneTemplatePage { - - /** The logger. */ - private static final Logger logger = getLogger(CreateSonePage.class.getName()); - - /** - * Creates a new “create Sone” page. - * - * @param template - * The template to render - * @param webInterface - * The Sone web interface - */ - public CreateSonePage(Template template, WebInterface webInterface) { - super("createSone.html", template, "Page.CreateSone.Title", webInterface, false); - } - - // - // STATIC ACCESSORS - // - - /** - * Returns a sorted list of all own identities that do not have the “Sone” - * context. - * - * @param core - * The core - * @return The list of own identities without the “Sone” context - */ - public static List getOwnIdentitiesWithoutSone(Core core) { - List identitiesWithoutSone = new ArrayList(); - Set allOwnIdentity = core.getIdentityManager().getAllOwnIdentities(); - for (OwnIdentity ownIdentity : allOwnIdentity) { - if (!ownIdentity.hasContext("Sone")) { - identitiesWithoutSone.add(ownIdentity); - } - } - Collections.sort(identitiesWithoutSone, new Comparator() { - - @Override - public int compare(OwnIdentity leftIdentity, OwnIdentity rightIdentity) { - return (leftIdentity.getNickname() + "@" + leftIdentity.getId()).compareToIgnoreCase(rightIdentity.getNickname() + "@" + rightIdentity.getId()); - } - }); - return identitiesWithoutSone; - } - - // - // TEMPLATEPAGE METHODS - // - - /** - * {@inheritDoc} - */ - @Override - protected void handleRequest(FreenetRequest request, TemplateContext templateContext) throws RedirectException { - List localSones = new ArrayList(webInterface.getCore().getLocalSones()); - Collections.sort(localSones, Sone.NICE_NAME_COMPARATOR); - templateContext.set("sones", localSones); - List ownIdentitiesWithoutSone = getOwnIdentitiesWithoutSone(webInterface.getCore()); - templateContext.set("identitiesWithoutSone", ownIdentitiesWithoutSone); - if (request.getMethod() == Method.POST) { - String id = request.getHttpRequest().getPartAsStringFailsafe("identity", 44); - OwnIdentity selectedIdentity = null; - for (OwnIdentity ownIdentity : ownIdentitiesWithoutSone) { - if (ownIdentity.getId().equals(id)) { - selectedIdentity = ownIdentity; - break; - } - } - if (selectedIdentity == null) { - templateContext.set("errorNoIdentity", true); - return; - } - /* create Sone. */ - Sone sone = webInterface.getCore().createSone(selectedIdentity); - if (sone == null) { - logger.log(Level.SEVERE, String.format("Could not create Sone for OwnIdentity: %s", selectedIdentity)); - /* TODO - go somewhere else */ - } - - /* log in the new Sone. */ - setCurrentSone(request.getToadletContext(), sone); - throw new RedirectException("index.html"); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isEnabled(ToadletContext toadletContext) { - if (webInterface.getCore().getPreferences().isRequireFullAccess() && !toadletContext.isAllowedFullAccess()) { - return false; - } - return (getCurrentSoneWithoutCreatingSession(toadletContext) == null) || (webInterface.getCore().getLocalSones().size() == 1); - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/web/CreateSonePage.kt b/src/main/kotlin/net/pterodactylus/sone/web/CreateSonePage.kt new file mode 100644 index 0000000..d2b0e4b --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/web/CreateSonePage.kt @@ -0,0 +1,44 @@ +package net.pterodactylus.sone.web + +import freenet.clients.http.ToadletContext +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.web.page.FreenetRequest +import net.pterodactylus.util.template.Template +import net.pterodactylus.util.template.TemplateContext +import net.pterodactylus.util.web.Method.POST +import java.util.logging.Level +import java.util.logging.Logger + +/** + * The “create Sone” page lets the user create a new Sone. + */ +class CreateSonePage(template: Template, webInterface: WebInterface): + SoneTemplatePage("createSone.html", template, "Page.CreateSone.Title", webInterface, false) { + + private val logger = Logger.getLogger(CreateSonePage::class.java.name) + + override fun handleRequest(request: FreenetRequest, templateContext: TemplateContext) { + templateContext["sones"] = webInterface.core.localSones.sortedWith(Sone.NICE_NAME_COMPARATOR) + templateContext["identitiesWithoutSone"] = webInterface.core.identityManager.allOwnIdentities.filterNot { "Sone" in it.contexts }.sortedBy { "${it.nickname}@${it.id}".toLowerCase() } + if (request.method == POST) { + val identity = request.httpRequest.getPartAsStringFailsafe("identity", 43) + webInterface.core.identityManager.allOwnIdentities.firstOrNull { it.id == identity }?.let { ownIdentity -> + val sone = webInterface.core.createSone(ownIdentity) + if (sone == null) { + logger.log(Level.SEVERE, "Could not create Sone for OwnIdentity: $ownIdentity") + } + setCurrentSone(request.toadletContext, sone) + throw RedirectException("index.html") + } + templateContext["errorNoIdentity"] = true + } + } + + override fun isEnabled(toadletContext: ToadletContext) = + if (webInterface.core.preferences.isRequireFullAccess && !toadletContext.isAllowedFullAccess) { + false + } else { + (getCurrentSone(toadletContext) == null) || (webInterface.core.localSones.size == 1) + } + +} diff --git a/src/test/java/net/pterodactylus/sone/web/CreateSonePageTest.java b/src/test/java/net/pterodactylus/sone/web/CreateSonePageTest.java deleted file mode 100644 index c7bb2f2..0000000 --- a/src/test/java/net/pterodactylus/sone/web/CreateSonePageTest.java +++ /dev/null @@ -1,167 +0,0 @@ -package net.pterodactylus.sone.web; - -import static net.pterodactylus.sone.web.WebTestUtils.redirectsTo; -import static net.pterodactylus.util.web.Method.POST; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.contains; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashSet; - -import net.pterodactylus.sone.data.Profile; -import net.pterodactylus.sone.data.Sone; -import net.pterodactylus.sone.freenet.wot.OwnIdentity; - -import org.junit.Test; -import org.mockito.invocation.InvocationOnMock; -import org.mockito.stubbing.Answer; - -/** - * Unit test for {@link CreateSonePage}. - * - * @author David ‘Bombe’ Roden - */ -public class CreateSonePageTest extends WebPageTest { - - private final CreateSonePage page = new CreateSonePage(template, webInterface); - private final Sone[] localSones = { createSone("local-sone1"), createSone("local-sone2"), createSone("local-sone3") }; - private final OwnIdentity[] ownIdentities = { - createOwnIdentity("own-id-1", "Sone"), - createOwnIdentity("own-id-2", "Test", "Foo"), - createOwnIdentity("own-id-3"), - createOwnIdentity("own-id-4", "Sone") - }; - - @Test - public void pageReturnsCorrectPath() { - assertThat(page.getPath(), is("createSone.html")); - } - - @Test - @SuppressWarnings("unchecked") - public void getRequestStoresListOfIdentitiesInTemplateContext() throws Exception { - addDefaultLocalSones(); - addDefaultOwnIdentities(); - page.processTemplate(freenetRequest, templateContext); - assertThat((Collection) templateContext.get("sones"), contains(localSones[0], localSones[1], localSones[2])); - assertThat((Collection) templateContext.get("identitiesWithoutSone"), contains(ownIdentities[1], ownIdentities[2])); - } - - private void addDefaultLocalSones() { - addLocalSone("local-sone3", localSones[2]); - addLocalSone("local-sone1", localSones[0]); - addLocalSone("local-sone2", localSones[1]); - } - - private void addDefaultOwnIdentities() { - addOwnIdentity(ownIdentities[2]); - addOwnIdentity(ownIdentities[0]); - addOwnIdentity(ownIdentities[3]); - addOwnIdentity(ownIdentities[1]); - } - - private Sone createSone(String id) { - Sone sone = mock(Sone.class); - when(sone.getId()).thenReturn(id); - when(sone.getProfile()).thenReturn(new Profile(sone)); - return sone; - } - - private OwnIdentity createOwnIdentity(String id, final String... contexts) { - OwnIdentity ownIdentity = mock(OwnIdentity.class); - when(ownIdentity.getId()).thenReturn(id); - when(ownIdentity.getNickname()).thenReturn(id); - when(ownIdentity.getContexts()).thenReturn(new HashSet<>(Arrays.asList(contexts))); - when(ownIdentity.hasContext(anyString())).thenAnswer(new Answer() { - @Override - public Boolean answer(InvocationOnMock invocation) throws Throwable { - return Arrays.asList(contexts).contains(invocation.getArgument(0)); - } - }); - return ownIdentity; - } - - @Test - public void soneIsCreatedAndLoggedIn() throws Exception { - addDefaultLocalSones(); - addDefaultOwnIdentities(); - addHttpRequestParameter("identity", "own-id-3"); - request("", POST); - Sone newSone = mock(Sone.class); - when(core.createSone(ownIdentities[2])).thenReturn(newSone); - expectedException.expect(redirectsTo("index.html")); - try { - page.processTemplate(freenetRequest, templateContext); - } finally { - verify(core).createSone(ownIdentities[2]); - verify(webInterface).setCurrentSone(toadletContext, newSone); - } - } - - @Test - public void onInvalidIdentityIdFlagIsStoredInTemplateContext() throws Exception { - addDefaultLocalSones(); - addDefaultOwnIdentities(); - addHttpRequestParameter("identity", "own-id-invalid"); - request("", POST); - page.processTemplate(freenetRequest, templateContext); - assertThat(((Boolean) templateContext.get("errorNoIdentity")), is(true)); - } - - @Test - public void ifSoneIsNotCreatedUserIsStillRedirectedToIndex() throws Exception { - addDefaultLocalSones(); - addDefaultOwnIdentities(); - addHttpRequestParameter("identity", "own-id-3"); - request("", POST); - when(core.createSone(ownIdentities[2])).thenReturn(null); - expectedException.expect(redirectsTo("index.html")); - try { - page.processTemplate(freenetRequest, templateContext); - } finally { - verify(core).createSone(ownIdentities[2]); - verify(webInterface).setCurrentSone(toadletContext, null); - } - } - - @Test - public void doNotShowCreateSoneInMenuIfFullAccessRequiredButClientHasNoFullAccess() { - core.getPreferences().setRequireFullAccess(true); - when(toadletContext.isAllowedFullAccess()).thenReturn(false); - assertThat(page.isEnabled(toadletContext), is(false)); - } - - @Test - public void showCreateSoneInMenuIfNotLoggedInAndClientHasFullAccess() { - core.getPreferences().setRequireFullAccess(true); - when(toadletContext.isAllowedFullAccess()).thenReturn(true); - unsetCurrentSone(); - assertThat(page.isEnabled(toadletContext), is(true)); - } - - @Test - public void showCreateSoneInMenuIfNotLoggedIn() { - unsetCurrentSone(); - assertThat(page.isEnabled(toadletContext), is(true)); - } - - @Test - public void showCreateSoneInMenuIfLoggedInAndASingleSoneExists() { - addLocalSone("local-sone", mock(Sone.class)); - assertThat(page.isEnabled(toadletContext), is(true)); - } - - @Test - public void doNotShowCreateSoneInMenuIfLoggedInAndMoreLocalSonesExists() { - addLocalSone("local-sone1", mock(Sone.class)); - addLocalSone("local-sone2", mock(Sone.class)); - assertThat(page.isEnabled(toadletContext), is(false)); - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/web/CreateSonePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/CreateSonePageTest.kt new file mode 100644 index 0000000..80239e9 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/CreateSonePageTest.kt @@ -0,0 +1,148 @@ +package net.pterodactylus.sone.web + +import net.pterodactylus.sone.data.Profile +import net.pterodactylus.sone.data.Sone +import net.pterodactylus.sone.freenet.wot.OwnIdentity +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.util.web.Method.POST +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.equalTo +import org.junit.Test +import org.mockito.ArgumentMatchers.anyString +import org.mockito.Mockito.verify + +/** + * Unit test for [CreateSonePage]. + */ +class CreateSonePageTest: WebPageTest() { + + private val page = CreateSonePage(template, webInterface) + override fun getPage() = page + + private val localSones_ = listOf( + createSone("local-sone1"), + createSone("local-sone2"), + createSone("local-sone3") + ) + + private fun createSone(id: String) = mock().apply { + whenever(this.id).thenReturn(id) + whenever(profile).thenReturn(Profile(this)) + } + + private val ownIdentities_ = listOf( + createOwnIdentity("own-id-1", "Sone"), + createOwnIdentity("own-id-2", "Test", "Foo"), + createOwnIdentity("own-id-3"), + createOwnIdentity("own-id-4", "Sone") + ) + + private fun createOwnIdentity(id: String, vararg contexts: String) = mock().apply { + whenever(this.id).thenReturn(id) + whenever(this.nickname).thenReturn(id) + whenever(this.contexts).thenReturn(contexts.toSet()) + whenever(this.hasContext(anyString())).thenAnswer { invocation -> invocation.getArgument(0) in contexts } + } + + @Test + fun `page returns correct path`() { + assertThat(page.path, equalTo("createSone.html")) + } + + @Test + fun `page does not require login`() { + assertThat(page.requiresLogin(), equalTo(false)) + } + + private fun addExistingSones() { + listOf(2, 0, 1).map { localSones_[it] }.forEach { addLocalSone(it.id, it) } + } + + @Test + @Suppress("UNCHECKED_CAST") + fun `get request stores sorted list of local sones in template context`() { + addExistingSones() + page.processTemplate(freenetRequest, templateContext) + assertThat(templateContext["sones"] as Collection, contains(localSones_[0], localSones_[1], localSones_[2])) + } + + private fun addExistingOwnIdentities() { + listOf(2, 0, 3, 1).map { ownIdentities_[it] }.forEach { addOwnIdentity(it) } + } + + @Test + @Suppress("UNCHECKED_CAST") + fun `get request stores sorted sones without sone context in the template context`() { + addExistingOwnIdentities() + page.processTemplate(freenetRequest, templateContext) + assertThat(templateContext["identitiesWithoutSone"] as Collection, contains(ownIdentities_[1], ownIdentities_[2])) + } + + @Test + fun `sone is created and logged in`() { + addExistingOwnIdentities() + request("", POST) + addHttpRequestParameter("identity", "own-id-3") + val newSone = mock() + whenever(core.createSone(ownIdentities_[2])).thenReturn(newSone) + verifyRedirect("index.html") { + verify(webInterface).setCurrentSone(toadletContext, newSone) + } + } + + @Test + fun `on invalid identity id a flag is set in the template context`() { + request("", POST) + addHttpRequestParameter("identity", "own-id-3") + page.processTemplate(freenetRequest, templateContext) + assertThat(templateContext["errorNoIdentity"], equalTo(true)) + } + + @Test + fun `if sone is not created user is still redirected to index`() { + addExistingOwnIdentities() + request("", POST) + addHttpRequestParameter("identity", "own-id-3") + whenever(core.createSone(ownIdentities_[2])).thenReturn(null) + verifyRedirect("index.html") { + verify(core).createSone(ownIdentities_[2]) + verify(webInterface).setCurrentSone(toadletContext, null) + } + } + + @Test + fun `create sone is not shown in menu if full access is required but client doesn’t have full access`() { + core.preferences.isRequireFullAccess = true + assertThat(page.isEnabled(toadletContext), equalTo(false)) + } + + @Test + fun `create sone is shown in menu if no sone is logged in`() { + unsetCurrentSone() + assertThat(page.isEnabled(toadletContext), equalTo(true)) + } + + @Test + fun `create sone is shown in menu if a single sone exists`() { + addLocalSone("local-sone", localSones_[0]) + assertThat(page.isEnabled(toadletContext), equalTo(true)) + } + + @Test + fun `create sone is not shown in menu if more than one sone exists`() { + addLocalSone("local-sone1", localSones_[0]) + addLocalSone("local-sone2", localSones_[1]) + assertThat(page.isEnabled(toadletContext), equalTo(false)) + } + + @Test + fun `create sone is shown in menu if no sone is logged in and client has full access`() { + core.preferences.isRequireFullAccess = true + whenever(toadletContext.isAllowedFullAccess).thenReturn(true) + unsetCurrentSone() + assertThat(page.isEnabled(toadletContext), equalTo(true)) + } + +} -- 2.7.4