🔀 Merge “release/v81” into “master”
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / core / ConfigurationSoneParserTest.kt
1 package net.pterodactylus.sone.core
2
3 import com.google.common.base.Optional.*
4 import net.pterodactylus.sone.core.ConfigurationSoneParser.*
5 import net.pterodactylus.sone.data.*
6 import net.pterodactylus.sone.database.*
7 import net.pterodactylus.sone.test.*
8 import net.pterodactylus.sone.test.Matchers.*
9 import net.pterodactylus.util.config.*
10 import org.hamcrest.MatcherAssert.*
11 import org.hamcrest.Matchers.*
12 import org.junit.*
13 import org.junit.rules.*
14 import org.mockito.ArgumentMatchers.*
15 import org.mockito.ArgumentMatchers.eq
16
17 /**
18  * Unit test for [ConfigurationSoneParser].
19  */
20 class ConfigurationSoneParserTest {
21
22         @Rule
23         @JvmField
24         val expectedException = ExpectedException.none()!!
25
26         private val configuration = mock<Configuration>()
27         private val sone = mock<Sone>().apply {
28                 whenever(this.id).thenReturn("1")
29         }
30         private val configurationSoneParser = ConfigurationSoneParser(configuration, sone)
31
32         @Test
33         fun emptyProfileIsLoadedCorrectly() {
34                 setupEmptyProfile()
35                 val profile = configurationSoneParser.parseProfile()
36                 assertThat(profile, notNullValue())
37                 assertThat(profile.firstName, nullValue())
38                 assertThat(profile.middleName, nullValue())
39                 assertThat(profile.lastName, nullValue())
40                 assertThat(profile.birthDay, nullValue())
41                 assertThat(profile.birthMonth, nullValue())
42                 assertThat(profile.birthYear, nullValue())
43                 assertThat(profile.fields, emptyIterable())
44         }
45
46         private fun setupEmptyProfile() {
47                 whenever(configuration.getStringValue(anyString())).thenReturn(TestValue.from(null))
48                 whenever(configuration.getIntValue(anyString())).thenReturn(TestValue.from(null))
49         }
50
51         @Test
52         fun filledProfileWithFieldsIsParsedCorrectly() {
53                 setupFilledProfile()
54                 val profile = configurationSoneParser.parseProfile()
55                 assertThat(profile, notNullValue())
56                 assertThat(profile.firstName, equalTo("First"))
57                 assertThat(profile.middleName, equalTo("M."))
58                 assertThat(profile.lastName, equalTo("Last"))
59                 assertThat(profile.birthDay, equalTo(18))
60                 assertThat(profile.birthMonth, equalTo(12))
61                 assertThat(profile.birthYear, equalTo(1976))
62                 val fields = profile.fields
63                 assertThat(fields, hasSize<Any>(2))
64                 assertThat(fields[0].name, equalTo("Field1"))
65                 assertThat(fields[0].value, equalTo("Value1"))
66                 assertThat(fields[1].name, equalTo("Field2"))
67                 assertThat(fields[1].value, equalTo("Value2"))
68         }
69
70         private fun setupFilledProfile() {
71                 setupString("Sone/1/Profile/FirstName", "First")
72                 setupString("Sone/1/Profile/MiddleName", "M.")
73                 setupString("Sone/1/Profile/LastName", "Last")
74                 setupInteger("Sone/1/Profile/BirthDay", 18)
75                 setupInteger("Sone/1/Profile/BirthMonth", 12)
76                 setupInteger("Sone/1/Profile/BirthYear", 1976)
77                 setupString("Sone/1/Profile/Fields/0/Name", "Field1")
78                 setupString("Sone/1/Profile/Fields/0/Value", "Value1")
79                 setupString("Sone/1/Profile/Fields/1/Name", "Field2")
80                 setupString("Sone/1/Profile/Fields/1/Value", "Value2")
81                 setupString("Sone/1/Profile/Fields/2/Name")
82         }
83
84         private fun setupString(nodeName: String, value: String? = null) {
85                 whenever(configuration.getStringValue(eq(nodeName))).thenReturn(TestValue.from(value))
86         }
87
88         private fun setupInteger(nodeName: String, value: Int?) {
89                 whenever(configuration.getIntValue(eq(nodeName))).thenReturn(TestValue.from(value))
90         }
91
92         @Test
93         fun postsAreParsedCorrectly() {
94                 setupCompletePosts()
95                 val postBuilderFactory = createPostBuilderFactory()
96                 val posts = configurationSoneParser.parsePosts(postBuilderFactory)
97                 assertThat(posts, containsInAnyOrder(
98                                 isPost("P0", 1000L, "T0", null),
99                                 isPost("P1", 1001L, "T1", "1234567890123456789012345678901234567890123")
100                 ))
101         }
102
103         private fun createPostBuilderFactory(): PostBuilderFactory {
104                 val postBuilderFactory = mock<PostBuilderFactory>()
105                 whenever(postBuilderFactory.newPostBuilder()).thenAnswer { TestPostBuilder() }
106                 return postBuilderFactory
107         }
108
109         private fun setupCompletePosts() {
110                 setupPost("0", "P0", 1000L, "T0")
111                 setupPost("1", "P1", 1001L, "T1", "1234567890123456789012345678901234567890123")
112                 setupPost("2")
113         }
114
115         private fun setupPost(postNumber: String, postId: String? = null, time: Long = 0, text: String? = null, recipientId: String? = null) {
116                 setupString("Sone/1/Posts/$postNumber/ID", postId)
117                 setupLong("Sone/1/Posts/$postNumber/Time", time)
118                 setupString("Sone/1/Posts/$postNumber/Text", text)
119                 setupString("Sone/1/Posts/$postNumber/Recipient", recipientId)
120         }
121
122         private fun setupLong(nodeName: String, value: Long?) {
123                 whenever(configuration.getLongValue(eq(nodeName))).thenReturn(TestValue.from(value))
124         }
125
126         @Test
127         fun postWithoutTimeIsRecognized() {
128                 setupPostWithoutTime()
129                 expectedException.expect<InvalidPostFound>()
130                 configurationSoneParser.parsePosts(createPostBuilderFactory())
131         }
132
133         private fun setupPostWithoutTime() {
134                 setupPost("0", "P0", 0L, "T0")
135         }
136
137         @Test
138         fun postWithoutTextIsRecognized() {
139                 setupPostWithoutText()
140                 expectedException.expect<InvalidPostFound>()
141                 configurationSoneParser.parsePosts(createPostBuilderFactory())
142         }
143
144         private fun setupPostWithoutText() {
145                 setupPost("0", "P0", 1000L)
146         }
147
148         @Test
149         fun postWithInvalidRecipientIdIsRecognized() {
150                 setupPostWithInvalidRecipientId()
151                 val posts = configurationSoneParser.parsePosts(createPostBuilderFactory())
152                 assertThat(posts, contains(isPost("P0", 1000L, "T0", null)))
153         }
154
155         private fun setupPostWithInvalidRecipientId() {
156                 setupPost("0", "P0", 1000L, "T0", "123")
157                 setupPost("1")
158         }
159
160         @Test
161         fun postRepliesAreParsedCorrectly() {
162                 setupPostReplies()
163                 val postReplyBuilderFactory = object : PostReplyBuilderFactory {
164                         override fun newPostReplyBuilder(): PostReplyBuilder {
165                                 return TestPostReplyBuilder()
166                         }
167                 }
168                 val postReplies = configurationSoneParser.parsePostReplies(postReplyBuilderFactory)
169                 assertThat(postReplies, hasSize(2))
170                 assertThat(postReplies, containsInAnyOrder(
171                                 isPostReply("R0", "P0", 1000L, "T0"),
172                                 isPostReply("R1", "P1", 1001L, "T1")
173                 ))
174         }
175
176         private fun setupPostReplies() {
177                 setupPostReply("0", "R0", "P0", 1000L, "T0")
178                 setupPostReply("1", "R1", "P1", 1001L, "T1")
179                 setupPostReply("2")
180         }
181
182         private fun setupPostReply(postReplyNumber: String, postReplyId: String? = null, postId: String? = null, time: Long = 0, text: String? = null) {
183                 setupString("Sone/1/Replies/$postReplyNumber/ID", postReplyId)
184                 setupString("Sone/1/Replies/$postReplyNumber/Post/ID", postId)
185                 setupLong("Sone/1/Replies/$postReplyNumber/Time", time)
186                 setupString("Sone/1/Replies/$postReplyNumber/Text", text)
187         }
188
189         @Test
190         fun missingPostIdIsRecognized() {
191                 setupPostReplyWithMissingPostId()
192                 expectedException.expect<InvalidPostReplyFound>()
193                 configurationSoneParser.parsePostReplies(null)
194         }
195
196         private fun setupPostReplyWithMissingPostId() {
197                 setupPostReply("0", "R0", null, 1000L, "T0")
198         }
199
200         @Test
201         fun missingPostReplyTimeIsRecognized() {
202                 setupPostReplyWithMissingPostReplyTime()
203                 expectedException.expect<InvalidPostReplyFound>()
204                 configurationSoneParser.parsePostReplies(null)
205         }
206
207         private fun setupPostReplyWithMissingPostReplyTime() {
208                 setupPostReply("0", "R0", "P0", 0L, "T0")
209         }
210
211         @Test
212         fun missingPostReplyTextIsRecognized() {
213                 setupPostReplyWithMissingPostReplyText()
214                 expectedException.expect<InvalidPostReplyFound>()
215                 configurationSoneParser.parsePostReplies(null)
216         }
217
218         private fun setupPostReplyWithMissingPostReplyText() {
219                 setupPostReply("0", "R0", "P0", 1000L)
220         }
221
222         @Test
223         fun likedPostIdsParsedCorrectly() {
224                 setupLikedPostIds()
225                 val likedPostIds = configurationSoneParser.parseLikedPostIds()
226                 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"))
227         }
228
229         private fun setupLikedPostIds() {
230                 setupString("Sone/1/Likes/Post/0/ID", "P1")
231                 setupString("Sone/1/Likes/Post/1/ID", "P2")
232                 setupString("Sone/1/Likes/Post/2/ID", "P3")
233                 setupString("Sone/1/Likes/Post/3/ID")
234         }
235
236         @Test
237         fun likedPostReplyIdsAreParsedCorrectly() {
238                 setupLikedPostReplyIds()
239                 val likedPostReplyIds = configurationSoneParser.parseLikedPostReplyIds()
240                 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"))
241         }
242
243         private fun setupLikedPostReplyIds() {
244                 setupString("Sone/1/Likes/Reply/0/ID", "R1")
245                 setupString("Sone/1/Likes/Reply/1/ID", "R2")
246                 setupString("Sone/1/Likes/Reply/2/ID", "R3")
247                 setupString("Sone/1/Likes/Reply/3/ID")
248         }
249
250         @Test
251         fun friendsAreParsedCorrectly() {
252                 setupFriends()
253                 val friends = configurationSoneParser.parseFriends()
254                 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"))
255         }
256
257         private fun setupFriends() {
258                 setupString("Sone/1/Friends/0/ID", "F1")
259                 setupString("Sone/1/Friends/1/ID", "F2")
260                 setupString("Sone/1/Friends/2/ID", "F3")
261                 setupString("Sone/1/Friends/3/ID")
262         }
263
264         @Test
265         fun topLevelAlbumsAreParsedCorrectly() {
266                 setupTopLevelAlbums()
267                 val albumBuilderFactory = createAlbumBuilderFactory()
268                 val topLevelAlbums = configurationSoneParser.parseTopLevelAlbums(albumBuilderFactory)
269                 assertThat(topLevelAlbums, hasSize<Any>(2))
270                 val firstAlbum = topLevelAlbums[0]
271                 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1"))
272                 assertThat(firstAlbum.albums, emptyIterable<Any>())
273                 assertThat<List<Image>>(firstAlbum.images, emptyIterable<Any>())
274                 val secondAlbum = topLevelAlbums[1]
275                 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2"))
276                 assertThat(secondAlbum.albums, hasSize<Any>(1))
277                 assertThat<List<Image>>(secondAlbum.images, emptyIterable<Any>())
278                 val thirdAlbum = secondAlbum.albums[0]
279                 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3"))
280                 assertThat(thirdAlbum.albums, emptyIterable<Any>())
281                 assertThat<List<Image>>(thirdAlbum.images, emptyIterable<Any>())
282         }
283
284         private fun setupTopLevelAlbums() {
285                 setupAlbum(0, "A1", null, "T1", "D1", "I1")
286                 setupAlbum(1, "A2", null, "T2", "D2")
287                 setupAlbum(2, "A3", "A2", "T3", "D3", "I3")
288                 setupAlbum(3)
289         }
290
291         private fun setupAlbum(albumNumber: Int, albumId: String? = null, parentAlbumId: String? = null, title: String? = null, description: String? = null, imageId: String? =null) {
292                 val albumPrefix = "Sone/1/Albums/$albumNumber"
293                 setupString("$albumPrefix/ID", albumId)
294                 setupString("$albumPrefix/Title", title)
295                 setupString("$albumPrefix/Description", description)
296                 setupString("$albumPrefix/Parent", parentAlbumId)
297                 setupString("$albumPrefix/AlbumImage", imageId)
298         }
299
300         private fun createAlbumBuilderFactory(): AlbumBuilderFactory {
301                 val albumBuilderFactory = mock<AlbumBuilderFactory>()
302                 whenever(albumBuilderFactory.newAlbumBuilder()).thenAnswer { TestAlbumBuilder() }
303                 return albumBuilderFactory
304         }
305
306         @Test
307         fun albumWithInvalidTitleIsRecognized() {
308                 setupAlbum(0, "A1", null, null, "D1", "I1")
309                 expectedException.expect<InvalidAlbumFound>()
310                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
311         }
312
313         @Test
314         fun albumWithInvalidDescriptionIsRecognized() {
315                 setupAlbum(0, "A1", null, "T1", null, "I1")
316                 expectedException.expect<InvalidAlbumFound>()
317                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
318         }
319
320         @Test
321         fun albumWithInvalidParentIsRecognized() {
322                 setupAlbum(0, "A1", "A0", "T1", "D1", "I1")
323                 expectedException.expect<InvalidParentAlbumFound>()
324                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
325         }
326
327         @Test
328         fun imagesAreParsedCorrectly() {
329                 setupTopLevelAlbums()
330                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
331                 setupImages()
332                 configurationSoneParser.parseImages(createImageBuilderFactory())
333                 val albums = configurationSoneParser.albums
334                 assertThat<List<Image>>(albums["A1"]!!.images, contains<Image>(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)))
335                 assertThat<List<Image>>(albums["A2"]!!.images, contains<Image>(isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)))
336                 assertThat<List<Image>>(albums["A3"]!!.images, contains<Image>(isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)))
337         }
338
339         private fun setupImages() {
340                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9)
341                 setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)
342                 setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)
343                 setupImage(3, null, null, 0L, null, null, null, 0, 0)
344         }
345
346         private fun setupImage(imageNumber: Int, id: String?, parentAlbumId: String?, creationTime: Long?, key: String?, title: String?, description: String?, width: Int?, height: Int?) {
347                 val imagePrefix = "Sone/1/Images/$imageNumber"
348                 setupString("$imagePrefix/ID", id)
349                 setupString("$imagePrefix/Album", parentAlbumId)
350                 setupLong("$imagePrefix/CreationTime", creationTime)
351                 setupString("$imagePrefix/Key", key)
352                 setupString("$imagePrefix/Title", title)
353                 setupString("$imagePrefix/Description", description)
354                 setupInteger("$imagePrefix/Width", width)
355                 setupInteger("$imagePrefix/Height", height)
356         }
357
358         private fun createImageBuilderFactory(): ImageBuilderFactory {
359                 val imageBuilderFactory = mock<ImageBuilderFactory>()
360                 whenever(imageBuilderFactory.newImageBuilder()).thenAnswer { TestImageBuilder() }
361                 return imageBuilderFactory
362         }
363
364         @Test
365         fun missingAlbumIdIsRecognized() {
366                 setupTopLevelAlbums()
367                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
368                 setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9)
369                 expectedException.expect<InvalidImageFound>()
370                 configurationSoneParser.parseImages(createImageBuilderFactory())
371         }
372
373         @Test
374         fun invalidAlbumIdIsRecognized() {
375                 setupTopLevelAlbums()
376                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
377                 setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9)
378                 expectedException.expect<InvalidParentAlbumFound>()
379                 configurationSoneParser.parseImages(createImageBuilderFactory())
380         }
381
382         @Test
383         fun missingCreationTimeIsRecognized() {
384                 setupTopLevelAlbums()
385                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
386                 setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9)
387                 expectedException.expect<InvalidImageFound>()
388                 configurationSoneParser.parseImages(createImageBuilderFactory())
389         }
390
391         @Test
392         fun missingKeyIsRecognized() {
393                 setupTopLevelAlbums()
394                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
395                 setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9)
396                 expectedException.expect<InvalidImageFound>()
397                 configurationSoneParser.parseImages(createImageBuilderFactory())
398         }
399
400         @Test
401         fun missingTitleIsRecognized() {
402                 setupTopLevelAlbums()
403                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
404                 setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9)
405                 expectedException.expect<InvalidImageFound>()
406                 configurationSoneParser.parseImages(createImageBuilderFactory())
407         }
408
409         @Test
410         fun missingDescriptionIsRecognized() {
411                 setupTopLevelAlbums()
412                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
413                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9)
414                 expectedException.expect<InvalidImageFound>()
415                 configurationSoneParser.parseImages(createImageBuilderFactory())
416         }
417
418         @Test
419         fun missingWidthIsRecognized() {
420                 setupTopLevelAlbums()
421                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
422                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9)
423                 expectedException.expect<InvalidImageFound>()
424                 configurationSoneParser.parseImages(createImageBuilderFactory())
425         }
426
427         @Test
428         fun missingHeightIsRecognized() {
429                 setupTopLevelAlbums()
430                 configurationSoneParser.parseTopLevelAlbums(createAlbumBuilderFactory())
431                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null)
432                 expectedException.expect<InvalidImageFound>()
433                 configurationSoneParser.parseImages(createImageBuilderFactory())
434         }
435
436 }