🎨 Replace UpdateFoundEvent with Kotlin version
[Sone.git] / src / test / java / net / pterodactylus / sone / core / ConfigurationSoneParserTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.of;
4 import static net.pterodactylus.sone.test.Matchers.isAlbum;
5 import static net.pterodactylus.sone.test.Matchers.isImage;
6 import static net.pterodactylus.sone.test.Matchers.isPost;
7 import static net.pterodactylus.sone.test.Matchers.isPostReply;
8 import static org.hamcrest.MatcherAssert.assertThat;
9 import static org.hamcrest.Matchers.contains;
10 import static org.hamcrest.Matchers.containsInAnyOrder;
11 import static org.hamcrest.Matchers.emptyIterable;
12 import static org.hamcrest.Matchers.hasSize;
13 import static org.hamcrest.Matchers.is;
14 import static org.hamcrest.Matchers.notNullValue;
15 import static org.hamcrest.Matchers.nullValue;
16 import static org.mockito.ArgumentMatchers.anyString;
17 import static org.mockito.ArgumentMatchers.eq;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.when;
20
21 import java.util.Collection;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25
26 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
27 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound;
28 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
29 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
30 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
31 import net.pterodactylus.sone.data.Album;
32 import net.pterodactylus.sone.data.Post;
33 import net.pterodactylus.sone.data.PostReply;
34 import net.pterodactylus.sone.data.Profile;
35 import net.pterodactylus.sone.data.Profile.Field;
36 import net.pterodactylus.sone.data.Sone;
37 import net.pterodactylus.sone.database.AlbumBuilder;
38 import net.pterodactylus.sone.database.AlbumBuilderFactory;
39 import net.pterodactylus.sone.database.ImageBuilder;
40 import net.pterodactylus.sone.database.ImageBuilderFactory;
41 import net.pterodactylus.sone.database.PostBuilder;
42 import net.pterodactylus.sone.database.PostBuilderFactory;
43 import net.pterodactylus.sone.database.PostReplyBuilder;
44 import net.pterodactylus.sone.database.PostReplyBuilderFactory;
45 import net.pterodactylus.sone.test.TestAlbumBuilder;
46 import net.pterodactylus.sone.test.TestImageBuilder;
47 import net.pterodactylus.sone.test.TestPostBuilder;
48 import net.pterodactylus.sone.test.TestPostReplyBuilder;
49 import net.pterodactylus.sone.test.TestValue;
50 import net.pterodactylus.util.config.Configuration;
51
52 import com.google.common.base.Optional;
53 import org.hamcrest.Matchers;
54 import org.junit.Test;
55 import org.mockito.invocation.InvocationOnMock;
56 import org.mockito.stubbing.Answer;
57
58 /**
59  * Unit test for {@link ConfigurationSoneParser}.
60  */
61 public class ConfigurationSoneParserTest {
62
63         private final Configuration configuration = mock(Configuration.class);
64         private final Sone sone = mock(Sone.class);
65         private final ConfigurationSoneParser configurationSoneParser;
66
67         public ConfigurationSoneParserTest() {
68                 when(sone.getId()).thenReturn("1");
69                 configurationSoneParser =
70                                 new ConfigurationSoneParser(configuration, sone);
71         }
72
73         @Test
74         public void emptyProfileIsLoadedCorrectly() {
75                 setupEmptyProfile();
76                 Profile profile = configurationSoneParser.parseProfile();
77                 assertThat(profile, notNullValue());
78                 assertThat(profile.getFirstName(), nullValue());
79                 assertThat(profile.getMiddleName(), nullValue());
80                 assertThat(profile.getLastName(), nullValue());
81                 assertThat(profile.getBirthDay(), nullValue());
82                 assertThat(profile.getBirthMonth(), nullValue());
83                 assertThat(profile.getBirthYear(), nullValue());
84                 assertThat(profile.getFields(), emptyIterable());
85         }
86
87         private void setupEmptyProfile() {
88                 when(configuration.getStringValue(anyString())).thenReturn(
89                                 TestValue.<String>from(null));
90                 when(configuration.getIntValue(anyString())).thenReturn(
91                                 TestValue.<Integer>from(null));
92         }
93
94         @Test
95         public void filledProfileWithFieldsIsParsedCorrectly() {
96                 setupFilledProfile();
97                 Profile profile = configurationSoneParser.parseProfile();
98                 assertThat(profile, notNullValue());
99                 assertThat(profile.getFirstName(), is("First"));
100                 assertThat(profile.getMiddleName(), is("M."));
101                 assertThat(profile.getLastName(), is("Last"));
102                 assertThat(profile.getBirthDay(), is(18));
103                 assertThat(profile.getBirthMonth(), is(12));
104                 assertThat(profile.getBirthYear(), is(1976));
105                 final List<Field> fields = profile.getFields();
106                 assertThat(fields, hasSize(2));
107                 assertThat(fields.get(0).getName(), is("Field1"));
108                 assertThat(fields.get(0).getValue(), is("Value1"));
109                 assertThat(fields.get(1).getName(), is("Field2"));
110                 assertThat(fields.get(1).getValue(), is("Value2"));
111         }
112
113         private void setupFilledProfile() {
114                 setupString("Sone/1/Profile/FirstName", "First");
115                 setupString("Sone/1/Profile/MiddleName", "M.");
116                 setupString("Sone/1/Profile/LastName", "Last");
117                 setupInteger("Sone/1/Profile/BirthDay", 18);
118                 setupInteger("Sone/1/Profile/BirthMonth", 12);
119                 setupInteger("Sone/1/Profile/BirthYear", 1976);
120                 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
121                 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
122                 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
123                 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
124                 setupString("Sone/1/Profile/Fields/2/Name", null);
125         }
126
127         private void setupString(String nodeName, String value) {
128                 when(configuration.getStringValue(eq(nodeName))).thenReturn(
129                                 TestValue.from(value));
130         }
131
132         private void setupInteger(String nodeName, Integer value) {
133                 when(configuration.getIntValue(eq(nodeName))).thenReturn(
134                                 TestValue.from(value));
135         }
136
137         @Test
138         public void postsAreParsedCorrectly() {
139                 setupCompletePosts();
140                 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
141                 Collection<Post> posts =
142                                 configurationSoneParser.parsePosts(postBuilderFactory);
143                 assertThat(posts,
144                                 Matchers.<Post>containsInAnyOrder(
145                                                 isPost("P0", 1000L, "T0", Optional.<String>absent()),
146                                                 isPost("P1", 1001L, "T1",
147                                                                 of("1234567890123456789012345678901234567890123"))));
148         }
149
150         private PostBuilderFactory createPostBuilderFactory() {
151                 PostBuilderFactory postBuilderFactory =
152                                 mock(PostBuilderFactory.class);
153                 when(postBuilderFactory.newPostBuilder()).thenAnswer(
154                                 new Answer<PostBuilder>() {
155                                         @Override
156                                         public PostBuilder answer(InvocationOnMock invocation)
157                                         throws Throwable {
158                                                 return new TestPostBuilder();
159                                         }
160                                 });
161                 return postBuilderFactory;
162         }
163
164         private void setupCompletePosts() {
165                 setupPost("0", "P0", 1000L, "T0", null);
166                 setupPost("1", "P1", 1001L, "T1",
167                                 "1234567890123456789012345678901234567890123");
168                 setupPost("2", null, 0L, null, null);
169         }
170
171         private void setupPost(String postNumber, String postId, long time,
172                         String text, String recipientId) {
173                 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
174                 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
175                 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
176                 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
177         }
178
179         private void setupLong(String nodeName, Long value) {
180                 when(configuration.getLongValue(eq(nodeName))).thenReturn(
181                                 TestValue.from(value));
182         }
183
184         @Test(expected = InvalidPostFound.class)
185         public void postWithoutTimeIsRecognized() {
186                 setupPostWithoutTime();
187                 configurationSoneParser.parsePosts(createPostBuilderFactory());
188         }
189
190         private void setupPostWithoutTime() {
191                 setupPost("0", "P0", 0L, "T0", null);
192         }
193
194         @Test(expected = InvalidPostFound.class)
195         public void postWithoutTextIsRecognized() {
196                 setupPostWithoutText();
197                 configurationSoneParser.parsePosts(createPostBuilderFactory());
198         }
199
200         private void setupPostWithoutText() {
201                 setupPost("0", "P0", 1000L, null, null);
202         }
203
204         @Test
205         public void postWithInvalidRecipientIdIsRecognized() {
206                 setupPostWithInvalidRecipientId();
207                 Collection<Post> posts = configurationSoneParser.parsePosts(
208                                 createPostBuilderFactory());
209                 assertThat(posts, contains(
210                                 isPost("P0", 1000L, "T0", Optional.<String>absent())));
211         }
212
213         private void setupPostWithInvalidRecipientId() {
214                 setupPost("0", "P0", 1000L, "T0", "123");
215                 setupPost("1", null, 0L, null, null);
216         }
217
218         @Test
219         public void postRepliesAreParsedCorrectly() {
220                 setupPostReplies();
221                 PostReplyBuilderFactory postReplyBuilderFactory =
222                                 new PostReplyBuilderFactory() {
223                                         @Override
224                                         public PostReplyBuilder newPostReplyBuilder() {
225                                                 return new TestPostReplyBuilder();
226                                         }
227                                 };
228                 Collection<PostReply> postReplies =
229                                 configurationSoneParser.parsePostReplies(
230                                                 postReplyBuilderFactory);
231                 assertThat(postReplies, hasSize(2));
232                 assertThat(postReplies,
233                                 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
234                                                 isPostReply("R1", "P1", 1001L, "T1")));
235         }
236
237         private void setupPostReplies() {
238                 setupPostReply("0", "R0", "P0", 1000L, "T0");
239                 setupPostReply("1", "R1", "P1", 1001L, "T1");
240                 setupPostReply("2", null, null, 0L, null);
241         }
242
243         private void setupPostReply(String postReplyNumber, String postReplyId,
244                         String postId, long time, String text) {
245                 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
246                 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
247                 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
248                 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
249         }
250
251         @Test(expected = InvalidPostReplyFound.class)
252         public void missingPostIdIsRecognized() {
253                 setupPostReplyWithMissingPostId();
254                 configurationSoneParser.parsePostReplies(null);
255         }
256
257         private void setupPostReplyWithMissingPostId() {
258                 setupPostReply("0", "R0", null, 1000L, "T0");
259         }
260
261         @Test(expected = InvalidPostReplyFound.class)
262         public void missingPostReplyTimeIsRecognized() {
263                 setupPostReplyWithMissingPostReplyTime();
264                 configurationSoneParser.parsePostReplies(null);
265         }
266
267         private void setupPostReplyWithMissingPostReplyTime() {
268                 setupPostReply("0", "R0", "P0", 0L, "T0");
269         }
270
271         @Test(expected = InvalidPostReplyFound.class)
272         public void missingPostReplyTextIsRecognized() {
273                 setupPostReplyWithMissingPostReplyText();
274                 configurationSoneParser.parsePostReplies(null);
275         }
276
277         private void setupPostReplyWithMissingPostReplyText() {
278                 setupPostReply("0", "R0", "P0", 1000L, null);
279         }
280
281         @Test
282         public void likedPostIdsParsedCorrectly() {
283                 setupLikedPostIds();
284                 Set<String> likedPostIds =
285                                 configurationSoneParser.parseLikedPostIds();
286                 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
287         }
288
289         private void setupLikedPostIds() {
290                 setupString("Sone/1/Likes/Post/0/ID", "P1");
291                 setupString("Sone/1/Likes/Post/1/ID", "P2");
292                 setupString("Sone/1/Likes/Post/2/ID", "P3");
293                 setupString("Sone/1/Likes/Post/3/ID", null);
294         }
295
296         @Test
297         public void likedPostReplyIdsAreParsedCorrectly() {
298                 setupLikedPostReplyIds();
299                 Set<String> likedPostReplyIds =
300                                 configurationSoneParser.parseLikedPostReplyIds();
301                 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
302         }
303
304         private void setupLikedPostReplyIds() {
305                 setupString("Sone/1/Likes/Reply/0/ID", "R1");
306                 setupString("Sone/1/Likes/Reply/1/ID", "R2");
307                 setupString("Sone/1/Likes/Reply/2/ID", "R3");
308                 setupString("Sone/1/Likes/Reply/3/ID", null);
309         }
310
311         @Test
312         public void friendsAreParsedCorrectly() {
313                 setupFriends();
314                 Set<String> friends = configurationSoneParser.parseFriends();
315                 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
316         }
317
318         private void setupFriends() {
319                 setupString("Sone/1/Friends/0/ID", "F1");
320                 setupString("Sone/1/Friends/1/ID", "F2");
321                 setupString("Sone/1/Friends/2/ID", "F3");
322                 setupString("Sone/1/Friends/3/ID", null);
323         }
324
325         @Test
326         public void topLevelAlbumsAreParsedCorrectly() {
327                 setupTopLevelAlbums();
328                 AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
329                 List<Album> topLevelAlbums =
330                                 configurationSoneParser.parseTopLevelAlbums(
331                                                 albumBuilderFactory);
332                 assertThat(topLevelAlbums, hasSize(2));
333                 Album firstAlbum = topLevelAlbums.get(0);
334                 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1"));
335                 assertThat(firstAlbum.getAlbums(), emptyIterable());
336                 assertThat(firstAlbum.getImages(), emptyIterable());
337                 Album secondAlbum = topLevelAlbums.get(1);
338                 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2"));
339                 assertThat(secondAlbum.getAlbums(), hasSize(1));
340                 assertThat(secondAlbum.getImages(), emptyIterable());
341                 Album thirdAlbum = secondAlbum.getAlbums().get(0);
342                 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3"));
343                 assertThat(thirdAlbum.getAlbums(), emptyIterable());
344                 assertThat(thirdAlbum.getImages(), emptyIterable());
345         }
346
347         private void setupTopLevelAlbums() {
348                 setupAlbum(0, "A1", null, "T1", "D1", "I1");
349                 setupAlbum(1, "A2", null, "T2", "D2", null);
350                 setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
351                 setupAlbum(3, null, null, null, null, null);
352         }
353
354         private void setupAlbum(int albumNumber, String albumId,
355                         String parentAlbumId,
356                         String title, String description, String imageId) {
357                 final String albumPrefix = "Sone/1/Albums/" + albumNumber;
358                 setupString(albumPrefix + "/ID", albumId);
359                 setupString(albumPrefix + "/Title", title);
360                 setupString(albumPrefix + "/Description", description);
361                 setupString(albumPrefix + "/Parent", parentAlbumId);
362                 setupString(albumPrefix + "/AlbumImage", imageId);
363         }
364
365         private AlbumBuilderFactory createAlbumBuilderFactory() {
366                 AlbumBuilderFactory albumBuilderFactory =
367                                 mock(AlbumBuilderFactory.class);
368                 when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
369                                 new Answer<AlbumBuilder>() {
370                                         @Override
371                                         public AlbumBuilder answer(InvocationOnMock invocation) {
372                                                 return new TestAlbumBuilder();
373                                         }
374                                 });
375                 return albumBuilderFactory;
376         }
377
378         @Test(expected = InvalidAlbumFound.class)
379         public void albumWithInvalidTitleIsRecognized() {
380                 setupAlbum(0, "A1", null, null, "D1", "I1");
381                 configurationSoneParser.parseTopLevelAlbums(
382                                 createAlbumBuilderFactory());
383         }
384
385         @Test(expected = InvalidAlbumFound.class)
386         public void albumWithInvalidDescriptionIsRecognized() {
387                 setupAlbum(0, "A1", null, "T1", null, "I1");
388                 configurationSoneParser.parseTopLevelAlbums(
389                                 createAlbumBuilderFactory());
390         }
391
392         @Test(expected = InvalidParentAlbumFound.class)
393         public void albumWithInvalidParentIsRecognized() {
394                 setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
395                 configurationSoneParser.parseTopLevelAlbums(
396                                 createAlbumBuilderFactory());
397         }
398
399         @Test
400         public void imagesAreParsedCorrectly() {
401                 setupTopLevelAlbums();
402                 configurationSoneParser.parseTopLevelAlbums(
403                                 createAlbumBuilderFactory());
404                 setupImages();
405                 configurationSoneParser.parseImages(createImageBuilderFactory());
406                 Map<String, Album> albums = configurationSoneParser.getAlbums();
407                 assertThat(albums.get("A1").getImages(),
408                                 contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)));
409                 assertThat(albums.get("A2").getImages(), contains(
410                                 isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)));
411                 assertThat(albums.get("A3").getImages(), contains(
412                                 isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)));
413         }
414
415         private void setupImages() {
416                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9);
417                 setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2);
418                 setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3);
419                 setupImage(3, null, null, 0L, null, null, null, 0, 0);
420         }
421
422         private void setupImage(int imageNumber, String id,
423                         String parentAlbumId, Long creationTime, String key, String title,
424                         String description, Integer width, Integer height) {
425                 final String imagePrefix = "Sone/1/Images/" + imageNumber;
426                 setupString(imagePrefix + "/ID", id);
427                 setupString(imagePrefix + "/Album", parentAlbumId);
428                 setupLong(imagePrefix + "/CreationTime", creationTime);
429                 setupString(imagePrefix + "/Key", key);
430                 setupString(imagePrefix + "/Title", title);
431                 setupString(imagePrefix + "/Description", description);
432                 setupInteger(imagePrefix + "/Width", width);
433                 setupInteger(imagePrefix + "/Height", height);
434         }
435
436         private ImageBuilderFactory createImageBuilderFactory() {
437                 ImageBuilderFactory imageBuilderFactory =
438                                 mock(ImageBuilderFactory.class);
439                 when(imageBuilderFactory.newImageBuilder()).thenAnswer(
440                                 new Answer<ImageBuilder>() {
441                                         @Override
442                                         public ImageBuilder answer(InvocationOnMock invocation)
443                                         throws Throwable {
444                                                 return new TestImageBuilder();
445                                         }
446                                 });
447                 return imageBuilderFactory;
448         }
449
450         @Test(expected = InvalidImageFound.class)
451         public void missingAlbumIdIsRecognized() {
452                 setupTopLevelAlbums();
453                 configurationSoneParser.parseTopLevelAlbums(
454                                 createAlbumBuilderFactory());
455                 setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9);
456                 configurationSoneParser.parseImages(createImageBuilderFactory());
457         }
458
459         @Test(expected = InvalidParentAlbumFound.class)
460         public void invalidAlbumIdIsRecognized() {
461                 setupTopLevelAlbums();
462                 configurationSoneParser.parseTopLevelAlbums(
463                                 createAlbumBuilderFactory());
464                 setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9);
465                 configurationSoneParser.parseImages(createImageBuilderFactory());
466         }
467
468         @Test(expected = InvalidImageFound.class)
469         public void missingCreationTimeIsRecognized() {
470                 setupTopLevelAlbums();
471                 configurationSoneParser.parseTopLevelAlbums(
472                                 createAlbumBuilderFactory());
473                 setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9);
474                 configurationSoneParser.parseImages(createImageBuilderFactory());
475         }
476
477         @Test(expected = InvalidImageFound.class)
478         public void missingKeyIsRecognized() {
479                 setupTopLevelAlbums();
480                 configurationSoneParser.parseTopLevelAlbums(
481                                 createAlbumBuilderFactory());
482                 setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9);
483                 configurationSoneParser.parseImages(createImageBuilderFactory());
484         }
485
486         @Test(expected = InvalidImageFound.class)
487         public void missingTitleIsRecognized() {
488                 setupTopLevelAlbums();
489                 configurationSoneParser.parseTopLevelAlbums(
490                                 createAlbumBuilderFactory());
491                 setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9);
492                 configurationSoneParser.parseImages(createImageBuilderFactory());
493         }
494
495         @Test(expected = InvalidImageFound.class)
496         public void missingDescriptionIsRecognized() {
497                 setupTopLevelAlbums();
498                 configurationSoneParser.parseTopLevelAlbums(
499                                 createAlbumBuilderFactory());
500                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9);
501                 configurationSoneParser.parseImages(createImageBuilderFactory());
502         }
503
504         @Test(expected = InvalidImageFound.class)
505         public void missingWidthIsRecognized() {
506                 setupTopLevelAlbums();
507                 configurationSoneParser.parseTopLevelAlbums(
508                                 createAlbumBuilderFactory());
509                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9);
510                 configurationSoneParser.parseImages(createImageBuilderFactory());
511         }
512
513         @Test(expected = InvalidImageFound.class)
514         public void missingHeightIsRecognized() {
515                 setupTopLevelAlbums();
516                 configurationSoneParser.parseTopLevelAlbums(
517                                 createAlbumBuilderFactory());
518                 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null);
519                 configurationSoneParser.parseImages(createImageBuilderFactory());
520         }
521
522 }