From 6b2461a58af4530997197ad3b17749f79c4d297a Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Sat, 26 Nov 2016 21:55:32 +0100 Subject: [PATCH] Add unit test for edit profile page --- .../net/pterodactylus/sone/web/WebPageTest.java | 44 ++-- .../pterodactylus/sone/web/EditProfilePageTest.kt | 224 +++++++++++++++++++++ 2 files changed, 255 insertions(+), 13 deletions(-) create mode 100644 src/test/kotlin/net/pterodactylus/sone/web/EditProfilePageTest.kt diff --git a/src/test/java/net/pterodactylus/sone/web/WebPageTest.java b/src/test/java/net/pterodactylus/sone/web/WebPageTest.java index b759a6d..c73bf61 100644 --- a/src/test/java/net/pterodactylus/sone/web/WebPageTest.java +++ b/src/test/java/net/pterodactylus/sone/web/WebPageTest.java @@ -64,6 +64,7 @@ public abstract class WebPageTest { protected final TemplateContext templateContext = new TemplateContext(); protected final HTTPRequest httpRequest = mock(HTTPRequest.class); + protected final Map requestParameters = new HashMap<>(); protected final Map requestHeaders = new HashMap<>(); protected final FreenetRequest freenetRequest = mock(FreenetRequest.class); protected final ToadletContext toadletContext = mock(ToadletContext.class); @@ -78,11 +79,37 @@ public abstract class WebPageTest { when(httpRequest.getPartAsStringFailsafe(anyString(), anyInt())).thenAnswer(new Answer() { @Override public String answer(InvocationOnMock invocation) throws Throwable { - return ""; + String parameter = invocation.getArgument(0); + int maxLength = invocation.getArgument(1); + return requestParameters.containsKey(parameter) ? requestParameters.get(parameter).substring(0, Math.min(maxLength, requestParameters.get(parameter).length())) : ""; + } + }); + when(httpRequest.getParam(anyString())).thenAnswer(new Answer() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + String parameter = invocation.getArgument(0); + return requestParameters.containsKey(parameter) ? requestParameters.get(parameter) : ""; + } + }); + when(httpRequest.getParam(anyString(), anyString())).thenAnswer(new Answer() { + @Override + public String answer(InvocationOnMock invocation) throws Throwable { + String parameter = invocation.getArgument(0); + return requestParameters.containsKey(parameter) ? requestParameters.get(parameter) : invocation.getArgument(1); + } + }); + when(httpRequest.isPartSet(anyString())).thenAnswer(new Answer() { + @Override + public Boolean answer(InvocationOnMock invocation) throws Throwable { + return requestParameters.containsKey(invocation.getArgument(0)); + } + }); + when(httpRequest.getParts()).thenAnswer(new Answer() { + @Override + public String[] answer(InvocationOnMock invocation) throws Throwable { + return requestParameters.keySet().toArray(new String[requestParameters.size()]); } }); - when(httpRequest.getParam(anyString())).thenReturn(""); - when(httpRequest.getParam(anyString(), anyString())).thenReturn(""); when(httpRequest.getHeader(anyString())).thenAnswer(new Answer() { @Override public String answer(InvocationOnMock invocation) throws Throwable { @@ -142,16 +169,7 @@ public abstract class WebPageTest { } protected void addHttpRequestParameter(String name, final String value) { - when(httpRequest.getPartAsStringFailsafe(eq(name), anyInt())).thenAnswer(new Answer() { - @Override - public String answer(InvocationOnMock invocation) throws Throwable { - int maxLength = invocation.getArgument(1); - return value.substring(0, Math.min(maxLength, value.length())); - } - }); - when(httpRequest.getParam(eq(name))).thenReturn(value); - when(httpRequest.getParam(eq(name), anyString())).thenReturn(value); - when(httpRequest.isPartSet(eq(name))).thenReturn(value != null && !value.isEmpty()); + requestParameters.put(name, value); } protected void addPost(String postId, Post post) { diff --git a/src/test/kotlin/net/pterodactylus/sone/web/EditProfilePageTest.kt b/src/test/kotlin/net/pterodactylus/sone/web/EditProfilePageTest.kt new file mode 100644 index 0000000..333d985 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/web/EditProfilePageTest.kt @@ -0,0 +1,224 @@ +package net.pterodactylus.sone.web + +import net.pterodactylus.sone.data.Image +import net.pterodactylus.sone.data.Profile +import net.pterodactylus.sone.test.mock +import net.pterodactylus.sone.test.whenever +import net.pterodactylus.util.web.Method.GET +import net.pterodactylus.util.web.Method.POST +import org.hamcrest.MatcherAssert.assertThat +import org.hamcrest.Matchers.contains +import org.hamcrest.Matchers.equalTo +import org.hamcrest.Matchers.notNullValue +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +/** + * Unit test for [EditProfilePage]. + */ +class EditProfilePageTest : WebPageTest() { + + private val page = EditProfilePage(template, webInterface) + + private val profile = Profile(currentSone) + private val firstField = profile.addField("First Field") + private val secondField = profile.addField("Second Field") + + @Before + fun setupProfile() { + val avatar = mock() + whenever(avatar.id).thenReturn("image-id") + whenever(avatar.sone).thenReturn(currentSone) + profile.firstName = "First" + profile.middleName = "Middle" + profile.lastName = "Last" + profile.birthDay = 31 + profile.birthMonth = 12 + profile.birthYear = 1999 + profile.setAvatar(avatar) + whenever(currentSone.profile).thenReturn(profile) + } + + @Test + fun `get request stores fields of current sone’s profile in template context`() { + request("", GET) + page.handleRequest(freenetRequest, templateContext) + assertThat(templateContext["firstName"], equalTo("First")) + assertThat(templateContext["middleName"], equalTo("Middle")) + assertThat(templateContext["lastName"], equalTo("Last")) + assertThat(templateContext["birthDay"], equalTo(31)) + assertThat(templateContext["birthMonth"], equalTo(12)) + assertThat(templateContext["birthYear"], equalTo(1999)) + assertThat(templateContext["avatarId"], equalTo("image-id")) + assertThat(templateContext["fields"], equalTo(listOf(firstField, secondField))) + } + + @Test + fun `post request without any command stores fields of current sone’s profile in template context`() { + request("", POST) + page.handleRequest(freenetRequest, templateContext) + assertThat(templateContext["firstName"], equalTo("First")) + assertThat(templateContext["middleName"], equalTo("Middle")) + assertThat(templateContext["lastName"], equalTo("Last")) + assertThat(templateContext["birthDay"], equalTo(31)) + assertThat(templateContext["birthMonth"], equalTo(12)) + assertThat(templateContext["birthYear"], equalTo(1999)) + assertThat(templateContext["avatarId"], equalTo("image-id")) + assertThat(templateContext["fields"], equalTo(listOf(firstField, secondField))) + } + + private fun verifySingleFieldCanBeChanged(fieldName: String, newValue: T, expectedValue: T = newValue, fieldAccessor: () -> T) { + request("", POST) + addHttpRequestParameter("save-profile", "true") + addHttpRequestParameter(fieldName, newValue.toString()) + expectedException.expect(WebTestUtils.redirectsTo("editProfile.html")) + try { + page.handleRequest(freenetRequest, templateContext) + } finally { + verify(core).touchConfiguration() + assertThat(fieldAccessor(), equalTo(expectedValue)) + } + } + + @Test + fun `post request with new first name and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("first-name", "New First") { profile.firstName } + } + + @Test + fun `post request with new middle name and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("middle-name", "New Middle") { profile.middleName } + } + + @Test + fun `post request with new last name and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("last-name", "New Last") { profile.lastName } + } + + @Test + fun `post request with new birth day and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("birth-day", 1) { profile.birthDay } + } + + @Test + fun `post request with new birth month and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("birth-month", 1) { profile.birthMonth } + } + + @Test + fun `post request with new birth year and save profile saves the profile and redirects back to profile edit page`() { + verifySingleFieldCanBeChanged("birth-year", 1) { profile.birthYear } + } + + @Test + fun `post request with new avatar ID and save profile saves the profile and redirects back to profile edit page`() { + val newAvatar = mock() + whenever(newAvatar.sone).thenReturn(currentSone) + whenever(newAvatar.id).thenReturn("avatar-id") + addImage("avatar-id", newAvatar) + verifySingleFieldCanBeChanged("avatarId", "avatar-id") { profile.avatar } + } + + @Test + fun `post request with field value saves profile and redirects back to profile edit page`() { + val field = profile.addField("name") + field.value = "old" + verifySingleFieldCanBeChanged("field-${field.id}", "new") { profile.getFieldByName("name").value } + } + + @Test + fun `post request with field value saves filtered value to profile and redirects back to profile edit page`() { + val field = profile.addField("name") + field.value = "old" + addHttpRequestHeader("Host", "www.te.st") + verifySingleFieldCanBeChanged("field-${field.id}", "http://www.te.st/KSK@GPL.txt", "KSK@GPL.txt") { profile.getFieldByName("name").value } + } + + @Test + fun `adding a field with a duplicate name sets error in template context`() { + request("", POST) + profile.addField("new-field") + addHttpRequestParameter("add-field", "true") + addHttpRequestParameter("field-name", "new-field") + page.handleRequest(freenetRequest, templateContext) + assertThat(templateContext["fieldName"], equalTo("new-field")) + assertThat(templateContext["duplicateFieldName"], equalTo(true)) + verify(core, never()).touchConfiguration() + } + + @Test + fun `adding a field with a new name sets adds field to profile and redirects to profile edit page`() { + request("", POST) + addHttpRequestParameter("add-field", "true") + addHttpRequestParameter("field-name", "new-field") + expectedException.expect(WebTestUtils.redirectsTo("editProfile.html#profile-fields")) + try { + page.handleRequest(freenetRequest, templateContext) + } finally { + assertThat(profile.getFieldByName("new-field"), notNullValue()) + verify(currentSone).profile = profile + verify(core).touchConfiguration() + } + } + + @Test + fun `deleting a field redirects to delete field page`() { + request("", POST) + addHttpRequestParameter("delete-field-${firstField.id}", "true") + expectedException.expect(WebTestUtils.redirectsTo("deleteProfileField.html?field=${firstField.id}")) + page.handleRequest(freenetRequest, templateContext) + } + + @Test + fun `moving a field up moves the field up and redirects to the edit profile page`() { + request("", POST) + addHttpRequestParameter("move-up-field-${secondField.id}", "true") + expectedException.expect(WebTestUtils.redirectsTo("editProfile.html#profile-fields")) + try { + page.handleRequest(freenetRequest, templateContext) + } finally { + assertThat(profile.fields, contains(secondField, firstField)) + verify(currentSone).profile = profile + } + } + + @Test + fun `moving an invalid field up redirects to the invalid page`() { + request("", POST) + addHttpRequestParameter("move-up-field-foo", "true") + expectedException.expect(WebTestUtils.redirectsTo("invalid.html")) + page.handleRequest(freenetRequest, templateContext) + } + + @Test + fun `moving a field down moves the field down and redirects to the edit profile page`() { + request("", POST) + addHttpRequestParameter("move-down-field-${firstField.id}", "true") + expectedException.expect(WebTestUtils.redirectsTo("editProfile.html#profile-fields")) + try { + page.handleRequest(freenetRequest, templateContext) + } finally { + assertThat(profile.fields, contains(secondField, firstField)) + verify(currentSone).profile = profile + } + } + + @Test + fun `moving an invalid field down redirects to the invalid page`() { + request("", POST) + addHttpRequestParameter("move-down-field-foo", "true") + expectedException.expect(WebTestUtils.redirectsTo("invalid.html")) + page.handleRequest(freenetRequest, templateContext) + } + + @Test + fun `editing a field redirects to the edit profile page`() { + request("", POST) + addHttpRequestParameter("edit-field-${firstField.id}", "true") + expectedException.expect(WebTestUtils.redirectsTo("editProfileField.html?field=${firstField.id}")) + page.handleRequest(freenetRequest, templateContext) + } + +} -- 2.7.4