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