package net.pterodactylus.sone.core import com.google.common.base.Optional.* import net.pterodactylus.sone.core.ConfigurationSoneParser.* import net.pterodactylus.sone.data.* import net.pterodactylus.sone.database.* import net.pterodactylus.sone.test.* import net.pterodactylus.sone.test.Matchers.* import net.pterodactylus.util.config.* import org.hamcrest.MatcherAssert.* import org.hamcrest.Matchers.* import org.junit.* import org.junit.rules.* import org.mockito.ArgumentMatchers.* import org.mockito.ArgumentMatchers.eq /** * Unit test for [ConfigurationSoneParser]. */ class ConfigurationSoneParserTest { @Rule @JvmField val expectedException = ExpectedException.none()!! private val configuration = mock() private val sone = mock().apply { whenever(this.id).thenReturn("1") } private val configurationSoneParser = ConfigurationSoneParser(configuration, sone) @Test fun emptyProfileIsLoadedCorrectly() { setupEmptyProfile() val profile = configurationSoneParser.parseProfile() assertThat(profile, notNullValue()) assertThat(profile.firstName, nullValue()) assertThat(profile.middleName, nullValue()) assertThat(profile.lastName, nullValue()) assertThat(profile.birthDay, nullValue()) assertThat(profile.birthMonth, nullValue()) assertThat(profile.birthYear, nullValue()) assertThat(profile.fields, emptyIterable()) } private fun setupEmptyProfile() { whenever(configuration.getStringValue(anyString())).thenReturn(TestValue.from(null)) whenever(configuration.getIntValue(anyString())).thenReturn(TestValue.from(null)) } @Test fun filledProfileWithFieldsIsParsedCorrectly() { setupFilledProfile() val profile = configurationSoneParser.parseProfile() assertThat(profile, notNullValue()) assertThat(profile.firstName, equalTo("First")) assertThat(profile.middleName, equalTo("M.")) assertThat(profile.lastName, equalTo("Last")) assertThat(profile.birthDay, equalTo(18)) assertThat(profile.birthMonth, equalTo(12)) assertThat(profile.birthYear, equalTo(1976)) val fields = profile.fields assertThat(fields, hasSize(2)) assertThat(fields[0].name, equalTo("Field1")) assertThat(fields[0].value, equalTo("Value1")) assertThat(fields[1].name, equalTo("Field2")) assertThat(fields[1].value, equalTo("Value2")) } private fun setupFilledProfile() { setupString("Sone/1/Profile/FirstName", "First") setupString("Sone/1/Profile/MiddleName", "M.") setupString("Sone/1/Profile/LastName", "Last") setupInteger("Sone/1/Profile/BirthDay", 18) setupInteger("Sone/1/Profile/BirthMonth", 12) setupInteger("Sone/1/Profile/BirthYear", 1976) setupString("Sone/1/Profile/Fields/0/Name", "Field1") setupString("Sone/1/Profile/Fields/0/Value", "Value1") setupString("Sone/1/Profile/Fields/1/Name", "Field2") setupString("Sone/1/Profile/Fields/1/Value", "Value2") setupString("Sone/1/Profile/Fields/2/Name") } private fun setupString(nodeName: String, value: String? = null) { whenever(configuration.getStringValue(eq(nodeName))).thenReturn(TestValue.from(value)) } private fun setupInteger(nodeName: String, value: Int?) { whenever(configuration.getIntValue(eq(nodeName))).thenReturn(TestValue.from(value)) } @Test fun postsAreParsedCorrectly() { setupCompletePosts() val postBuilderFactory = createPostBuilderFactory() val posts = configurationSoneParser.parsePosts(postBuilderFactory) assertThat(posts, containsInAnyOrder( isPost("P0", 1000L, "T0", absent()), isPost("P1", 1001L, "T1", of("1234567890123456789012345678901234567890123")) )) } private fun createPostBuilderFactory(): PostBuilderFactory { val postBuilderFactory = mock() whenever(postBuilderFactory.newPostBuilder()).thenAnswer { TestPostBuilder() } return postBuilderFactory } private fun setupCompletePosts() { setupPost("0", "P0", 1000L, "T0") setupPost("1", "P1", 1001L, "T1", "1234567890123456789012345678901234567890123") setupPost("2") } private fun setupPost(postNumber: String, postId: String? = null, time: Long = 0, text: String? = null, recipientId: String? = null) { setupString("Sone/1/Posts/$postNumber/ID", postId) setupLong("Sone/1/Posts/$postNumber/Time", time) setupString("Sone/1/Posts/$postNumber/Text", text) setupString("Sone/1/Posts/$postNumber/Recipient", recipientId) } private fun setupLong(nodeName: String, value: Long?) { whenever(configuration.getLongValue(eq(nodeName))).thenReturn(TestValue.from(value)) } @Test fun postWithoutTimeIsRecognized() { setupPostWithoutTime() expectedException.expect() configurationSoneParser.parsePosts(createPostBuilderFactory()) } private fun setupPostWithoutTime() { setupPost("0", "P0", 0L, "T0") } @Test fun postWithoutTextIsRecognized() { setupPostWithoutText() expectedException.expect() configurationSoneParser.parsePosts(createPostBuilderFactory()) } private fun setupPostWithoutText() { setupPost("0", "P0", 1000L) } @Test fun postWithInvalidRecipientIdIsRecognized() { setupPostWithInvalidRecipientId() val posts = configurationSoneParser.parsePosts(createPostBuilderFactory()) assertThat(posts, contains(isPost("P0", 1000L, "T0", absent()))) } private fun setupPostWithInvalidRecipientId() { setupPost("0", "P0", 1000L, "T0", "123") setupPost("1") } @Test fun postRepliesAreParsedCorrectly() { setupPostReplies() val postReplyBuilderFactory = object : PostReplyBuilderFactory { override fun newPostReplyBuilder(): PostReplyBuilder { return TestPostReplyBuilder() } } val postReplies = configurationSoneParser.parsePostReplies(postReplyBuilderFactory) assertThat(postReplies, hasSize(2)) assertThat(postReplies, containsInAnyOrder( isPostReply("R0", "P0", 1000L, "T0"), isPostReply("R1", "P1", 1001L, "T1") )) } private fun setupPostReplies() { setupPostReply("0", "R0", "P0", 1000L, "T0") setupPostReply("1", "R1", "P1", 1001L, "T1") setupPostReply("2") } private fun setupPostReply(postReplyNumber: String, postReplyId: String? = null, postId: String? = null, time: Long = 0, text: String? = null) { setupString("Sone/1/Replies/$postReplyNumber/ID", postReplyId) setupString("Sone/1/Replies/$postReplyNumber/Post/ID", postId) setupLong("Sone/1/Replies/$postReplyNumber/Time", time) setupString("Sone/1/Replies/$postReplyNumber/Text", text) } @Test fun missingPostIdIsRecognized() { setupPostReplyWithMissingPostId() expectedException.expect() configurationSoneParser.parsePostReplies(null) } private fun setupPostReplyWithMissingPostId() { setupPostReply("0", "R0", null, 1000L, "T0") } @Test fun missingPostReplyTimeIsRecognized() { setupPostReplyWithMissingPostReplyTime() expectedException.expect() configurationSoneParser.parsePostReplies(null) } private fun setupPostReplyWithMissingPostReplyTime() { setupPostReply("0", "R0", "P0", 0L, "T0") } @Test fun missingPostReplyTextIsRecognized() { setupPostReplyWithMissingPostReplyText() expectedException.expect() configurationSoneParser.parsePostReplies(null) } private fun setupPostReplyWithMissingPostReplyText() { setupPostReply("0", "R0", "P0", 1000L) } @Test fun likedPostIdsParsedCorrectly() { setupLikedPostIds() val likedPostIds = configurationSoneParser.parseLikedPostIds() assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3")) } private fun setupLikedPostIds() { setupString("Sone/1/Likes/Post/0/ID", "P1") setupString("Sone/1/Likes/Post/1/ID", "P2") setupString("Sone/1/Likes/Post/2/ID", "P3") setupString("Sone/1/Likes/Post/3/ID") } @Test fun likedPostReplyIdsAreParsedCorrectly() { setupLikedPostReplyIds() val likedPostReplyIds = configurationSoneParser.parseLikedPostReplyIds() assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3")) } private fun setupLikedPostReplyIds() { setupString("Sone/1/Likes/Reply/0/ID", "R1") setupString("Sone/1/Likes/Reply/1/ID", "R2") setupString("Sone/1/Likes/Reply/2/ID", "R3") setupString("Sone/1/Likes/Reply/3/ID") } @Test fun friendsAreParsedCorrectly() { setupFriends() val friends = configurationSoneParser.parseFriends() assertThat(friends, containsInAnyOrder("F1", "F2", "F3")) } private fun setupFriends() { setupString("Sone/1/Friends/0/ID", "F1") setupString("Sone/1/Friends/1/ID", "F2") setupString("Sone/1/Friends/2/ID", "F3") setupString("Sone/1/Friends/3/ID") } @Test fun topLevelAlbumsAreParsedCorrectly() { setupTopLevelAlbums() val albumBuilderFactory = createAlbumBuilderFactory() val topLevelAlbums = configurationSoneParser.parseTopLevelAlbums(albumBuilderFactory) assertThat(topLevelAlbums, hasSize(2)) val firstAlbum = topLevelAlbums[0] assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1")) assertThat(firstAlbum.albums, emptyIterable()) assertThat>(firstAlbum.images, emptyIterable()) val secondAlbum = topLevelAlbums[1] assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2")) assertThat(secondAlbum.albums, hasSize(1)) assertThat>(secondAlbum.images, emptyIterable()) val thirdAlbum = secondAlbum.albums[0] assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3")) assertThat(thirdAlbum.albums, emptyIterable()) assertThat>(thirdAlbum.images, emptyIterable()) } private fun setupTopLevelAlbums() { setupAlbum(0, "A1", null, "T1", "D1", "I1") setupAlbum(1, "A2", null, "T2", "D2") setupAlbum(2, "A3", "A2", "T3", "D3", "I3") setupAlbum(3) } private fun setupAlbum(albumNumber: Int, albumId: String? = null, parentAlbumId: String? = null, title: String? = null, description: String? = null, imageId: String? =null) { val albumPrefix = "Sone/1/Albums/$albumNumber" setupString("$albumPrefix/ID", albumId) setupString("$albumPrefix/Title", title) setupString("$albumPrefix/Description", description) setupString("$albumPrefix/Parent", parentAlbumId) setupString("$albumPrefix/AlbumImage", imageId) } private fun createAlbumBuilderFactory(): AlbumBuilderFactory { val albumBuilderFactory = mock() whenever(albumBuilderFactory.newAlbumBuilder()).thenAnswer { TestAlbumBuilder() } return albumBuilderFactory } @Test fun albumWithInvalidTitleIsRecognized() { setupAlbum(0, "A1", null, null, "D1", "I1") expectedException.expect() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) } @Test fun albumWithInvalidDescriptionIsRecognized() { setupAlbum(0, "A1", null, "T1", null, "I1") expectedException.expect() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) } @Test fun albumWithInvalidParentIsRecognized() { setupAlbum(0, "A1", "A0", "T1", "D1", "I1") expectedException.expect() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) } @Test fun imagesAreParsedCorrectly() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImages() configurationSoneParser.parseImages(createImageBuilderFactory()) val albums = configurationSoneParser.albums assertThat>(albums["A1"]!!.images, contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9))) assertThat>(albums["A2"]!!.images, contains(isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2))) assertThat>(albums["A3"]!!.images, contains(isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3))) } private fun setupImages() { setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9) setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2) setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3) setupImage(3, null, null, 0L, null, null, null, 0, 0) } private fun setupImage(imageNumber: Int, id: String?, parentAlbumId: String?, creationTime: Long?, key: String?, title: String?, description: String?, width: Int?, height: Int?) { val imagePrefix = "Sone/1/Images/$imageNumber" setupString("$imagePrefix/ID", id) setupString("$imagePrefix/Album", parentAlbumId) setupLong("$imagePrefix/CreationTime", creationTime) setupString("$imagePrefix/Key", key) setupString("$imagePrefix/Title", title) setupString("$imagePrefix/Description", description) setupInteger("$imagePrefix/Width", width) setupInteger("$imagePrefix/Height", height) } private fun createImageBuilderFactory(): ImageBuilderFactory { val imageBuilderFactory = mock() whenever(imageBuilderFactory.newImageBuilder()).thenAnswer { TestImageBuilder() } return imageBuilderFactory } @Test fun missingAlbumIdIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun invalidAlbumIdIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingCreationTimeIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingKeyIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingTitleIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingDescriptionIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingWidthIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } @Test fun missingHeightIsRecognized() { setupTopLevelAlbums() configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory()) setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null) expectedException.expect() configurationSoneParser.parseImages(createImageBuilderFactory()) } }