1 package net.pterodactylus.sone.core;
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;
21 import java.util.Collection;
22 import java.util.List;
25 import java.util.concurrent.atomic.AtomicReference;
27 import net.pterodactylus.sone.TestAlbumBuilder;
28 import net.pterodactylus.sone.TestImageBuilder;
29 import net.pterodactylus.sone.TestPostBuilder;
30 import net.pterodactylus.sone.TestPostReplyBuilder;
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 import net.pterodactylus.util.config.ConfigurationException;
52 import net.pterodactylus.util.config.Value;
54 import com.google.common.base.Optional;
55 import org.hamcrest.Matchers;
56 import org.junit.Test;
57 import org.mockito.invocation.InvocationOnMock;
58 import org.mockito.stubbing.Answer;
61 * Unit test for {@link ConfigurationSoneParser}.
63 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
65 public class ConfigurationSoneParserTest {
67 private final Configuration configuration = mock(Configuration.class);
68 private final Sone sone = mock(Sone.class);
69 private final ConfigurationSoneParser configurationSoneParser;
71 public ConfigurationSoneParserTest() {
72 when(sone.getId()).thenReturn("1");
73 configurationSoneParser =
74 new ConfigurationSoneParser(configuration, sone);
78 public void emptyProfileIsLoadedCorrectly() {
80 Profile profile = configurationSoneParser.parseProfile();
81 assertThat(profile, notNullValue());
82 assertThat(profile.getFirstName(), nullValue());
83 assertThat(profile.getMiddleName(), nullValue());
84 assertThat(profile.getLastName(), nullValue());
85 assertThat(profile.getBirthDay(), nullValue());
86 assertThat(profile.getBirthMonth(), nullValue());
87 assertThat(profile.getBirthYear(), nullValue());
88 assertThat(profile.getFields(), emptyIterable());
91 private void setupEmptyProfile() {
92 when(configuration.getStringValue(anyString())).thenReturn(
93 new TestValue<String>(null));
94 when(configuration.getIntValue(anyString())).thenReturn(
95 new TestValue<Integer>(null));
99 public void filledProfileWithFieldsIsParsedCorrectly() {
100 setupFilledProfile();
101 Profile profile = configurationSoneParser.parseProfile();
102 assertThat(profile, notNullValue());
103 assertThat(profile.getFirstName(), is("First"));
104 assertThat(profile.getMiddleName(), is("M."));
105 assertThat(profile.getLastName(), is("Last"));
106 assertThat(profile.getBirthDay(), is(18));
107 assertThat(profile.getBirthMonth(), is(12));
108 assertThat(profile.getBirthYear(), is(1976));
109 final List<Field> fields = profile.getFields();
110 assertThat(fields, hasSize(2));
111 assertThat(fields.get(0).getName(), is("Field1"));
112 assertThat(fields.get(0).getValue(), is("Value1"));
113 assertThat(fields.get(1).getName(), is("Field2"));
114 assertThat(fields.get(1).getValue(), is("Value2"));
117 private void setupFilledProfile() {
118 setupString("Sone/1/Profile/FirstName", "First");
119 setupString("Sone/1/Profile/MiddleName", "M.");
120 setupString("Sone/1/Profile/LastName", "Last");
121 setupInteger("Sone/1/Profile/BirthDay", 18);
122 setupInteger("Sone/1/Profile/BirthMonth", 12);
123 setupInteger("Sone/1/Profile/BirthYear", 1976);
124 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
125 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
126 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
127 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
128 setupString("Sone/1/Profile/Fields/2/Name", null);
131 private void setupString(String nodeName, String value) {
132 when(configuration.getStringValue(eq(nodeName))).thenReturn(
133 new TestValue<String>(value));
136 private void setupInteger(String nodeName, Integer value) {
137 when(configuration.getIntValue(eq(nodeName))).thenReturn(
138 new TestValue<Integer>(value));
142 public void postsAreParsedCorrectly() {
143 setupCompletePosts();
144 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
145 Collection<Post> posts =
146 configurationSoneParser.parsePosts(postBuilderFactory);
148 Matchers.<Post>containsInAnyOrder(
149 isPost("P0", 1000L, "T0", Optional.<String>absent()),
150 isPost("P1", 1001L, "T1",
151 of("1234567890123456789012345678901234567890123"))));
154 private PostBuilderFactory createPostBuilderFactory() {
155 PostBuilderFactory postBuilderFactory =
156 mock(PostBuilderFactory.class);
157 when(postBuilderFactory.newPostBuilder()).thenAnswer(
158 new Answer<PostBuilder>() {
160 public PostBuilder answer(InvocationOnMock invocation)
162 return new TestPostBuilder();
165 return postBuilderFactory;
168 private void setupCompletePosts() {
169 setupPost("0", "P0", 1000L, "T0", null);
170 setupPost("1", "P1", 1001L, "T1",
171 "1234567890123456789012345678901234567890123");
172 setupPost("2", null, 0L, null, null);
175 private void setupPost(String postNumber, String postId, long time,
176 String text, String recipientId) {
177 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
178 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
179 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
180 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
183 private void setupLong(String nodeName, Long value) {
184 when(configuration.getLongValue(eq(nodeName))).thenReturn(
185 new TestValue<Long>(value));
188 @Test(expected = InvalidPostFound.class)
189 public void postWithoutTimeIsRecognized() {
190 setupPostWithoutTime();
191 configurationSoneParser.parsePosts(createPostBuilderFactory());
194 private void setupPostWithoutTime() {
195 setupPost("0", "P0", 0L, "T0", null);
198 @Test(expected = InvalidPostFound.class)
199 public void postWithoutTextIsRecognized() {
200 setupPostWithoutText();
201 configurationSoneParser.parsePosts(createPostBuilderFactory());
204 private void setupPostWithoutText() {
205 setupPost("0", "P0", 1000L, null, null);
209 public void postWithInvalidRecipientIdIsRecognized() {
210 setupPostWithInvalidRecipientId();
211 Collection<Post> posts = configurationSoneParser.parsePosts(
212 createPostBuilderFactory());
213 assertThat(posts, contains(
214 isPost("P0", 1000L, "T0", Optional.<String>absent())));
217 private void setupPostWithInvalidRecipientId() {
218 setupPost("0", "P0", 1000L, "T0", "123");
219 setupPost("1", null, 0L, null, null);
223 public void postRepliesAreParsedCorrectly() {
225 PostReplyBuilderFactory postReplyBuilderFactory =
226 new PostReplyBuilderFactory() {
228 public PostReplyBuilder newPostReplyBuilder() {
229 return new TestPostReplyBuilder();
232 Collection<PostReply> postReplies =
233 configurationSoneParser.parsePostReplies(
234 postReplyBuilderFactory);
235 assertThat(postReplies, hasSize(2));
236 assertThat(postReplies,
237 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
238 isPostReply("R1", "P1", 1001L, "T1")));
241 private void setupPostReplies() {
242 setupPostReply("0", "R0", "P0", 1000L, "T0");
243 setupPostReply("1", "R1", "P1", 1001L, "T1");
244 setupPostReply("2", null, null, 0L, null);
247 private void setupPostReply(String postReplyNumber, String postReplyId,
248 String postId, long time, String text) {
249 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
250 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
251 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
252 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
255 @Test(expected = InvalidPostReplyFound.class)
256 public void missingPostIdIsRecognized() {
257 setupPostReplyWithMissingPostId();
258 configurationSoneParser.parsePostReplies(null);
261 private void setupPostReplyWithMissingPostId() {
262 setupPostReply("0", "R0", null, 1000L, "T0");
265 @Test(expected = InvalidPostReplyFound.class)
266 public void missingPostReplyTimeIsRecognized() {
267 setupPostReplyWithMissingPostReplyTime();
268 configurationSoneParser.parsePostReplies(null);
271 private void setupPostReplyWithMissingPostReplyTime() {
272 setupPostReply("0", "R0", "P0", 0L, "T0");
275 @Test(expected = InvalidPostReplyFound.class)
276 public void missingPostReplyTextIsRecognized() {
277 setupPostReplyWithMissingPostReplyText();
278 configurationSoneParser.parsePostReplies(null);
281 private void setupPostReplyWithMissingPostReplyText() {
282 setupPostReply("0", "R0", "P0", 1000L, null);
286 public void likedPostIdsParsedCorrectly() {
288 Set<String> likedPostIds =
289 configurationSoneParser.parseLikedPostIds();
290 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
293 private void setupLikedPostIds() {
294 setupString("Sone/1/Likes/Post/0/ID", "P1");
295 setupString("Sone/1/Likes/Post/1/ID", "P2");
296 setupString("Sone/1/Likes/Post/2/ID", "P3");
297 setupString("Sone/1/Likes/Post/3/ID", null);
301 public void likedPostReplyIdsAreParsedCorrectly() {
302 setupLikedPostReplyIds();
303 Set<String> likedPostReplyIds =
304 configurationSoneParser.parseLikedPostReplyIds();
305 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
308 private void setupLikedPostReplyIds() {
309 setupString("Sone/1/Likes/Reply/0/ID", "R1");
310 setupString("Sone/1/Likes/Reply/1/ID", "R2");
311 setupString("Sone/1/Likes/Reply/2/ID", "R3");
312 setupString("Sone/1/Likes/Reply/3/ID", null);
316 public void friendsAreParsedCorrectly() {
318 Set<String> friends = configurationSoneParser.parseFriends();
319 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
322 private void setupFriends() {
323 setupString("Sone/1/Friends/0/ID", "F1");
324 setupString("Sone/1/Friends/1/ID", "F2");
325 setupString("Sone/1/Friends/2/ID", "F3");
326 setupString("Sone/1/Friends/3/ID", null);
330 public void topLevelAlbumsAreParsedCorrectly() {
331 setupTopLevelAlbums();
332 AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
333 List<Album> topLevelAlbums =
334 configurationSoneParser.parseTopLevelAlbums(
335 albumBuilderFactory);
336 assertThat(topLevelAlbums, hasSize(2));
337 Album firstAlbum = topLevelAlbums.get(0);
338 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1", "I1"));
339 assertThat(firstAlbum.getAlbums(), emptyIterable());
340 assertThat(firstAlbum.getImages(), emptyIterable());
341 Album secondAlbum = topLevelAlbums.get(1);
342 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2", null));
343 assertThat(secondAlbum.getAlbums(), hasSize(1));
344 assertThat(secondAlbum.getImages(), emptyIterable());
345 Album thirdAlbum = secondAlbum.getAlbums().get(0);
346 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3", "I3"));
347 assertThat(thirdAlbum.getAlbums(), emptyIterable());
348 assertThat(thirdAlbum.getImages(), emptyIterable());
351 private void setupTopLevelAlbums() {
352 setupAlbum(0, "A1", null, "T1", "D1", "I1");
353 setupAlbum(1, "A2", null, "T2", "D2", null);
354 setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
355 setupAlbum(3, null, null, null, null, null);
358 private void setupAlbum(int albumNumber, String albumId,
359 String parentAlbumId,
360 String title, String description, String imageId) {
361 final String albumPrefix = "Sone/1/Albums/" + albumNumber;
362 setupString(albumPrefix + "/ID", albumId);
363 setupString(albumPrefix + "/Title", title);
364 setupString(albumPrefix + "/Description", description);
365 setupString(albumPrefix + "/Parent", parentAlbumId);
366 setupString(albumPrefix + "/AlbumImage", imageId);
369 private AlbumBuilderFactory createAlbumBuilderFactory() {
370 AlbumBuilderFactory albumBuilderFactory =
371 mock(AlbumBuilderFactory.class);
372 when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
373 new Answer<AlbumBuilder>() {
375 public AlbumBuilder answer(InvocationOnMock invocation) {
376 return new TestAlbumBuilder();
379 return albumBuilderFactory;
382 @Test(expected = InvalidAlbumFound.class)
383 public void albumWithInvalidTitleIsRecognized() {
384 setupAlbum(0, "A1", null, null, "D1", "I1");
385 configurationSoneParser.parseTopLevelAlbums(
386 createAlbumBuilderFactory());
389 @Test(expected = InvalidAlbumFound.class)
390 public void albumWithInvalidDescriptionIsRecognized() {
391 setupAlbum(0, "A1", null, "T1", null, "I1");
392 configurationSoneParser.parseTopLevelAlbums(
393 createAlbumBuilderFactory());
396 @Test(expected = InvalidParentAlbumFound.class)
397 public void albumWithInvalidParentIsRecognized() {
398 setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
399 configurationSoneParser.parseTopLevelAlbums(
400 createAlbumBuilderFactory());
404 public void imagesAreParsedCorrectly() {
405 setupTopLevelAlbums();
406 configurationSoneParser.parseTopLevelAlbums(
407 createAlbumBuilderFactory());
409 configurationSoneParser.parseImages(createImageBuilderFactory());
410 Map<String, Album> albums = configurationSoneParser.getAlbums();
411 assertThat(albums.get("A1").getImages(),
412 contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)));
413 assertThat(albums.get("A2").getImages(), contains(
414 isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)));
415 assertThat(albums.get("A3").getImages(), contains(
416 isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)));
419 private void setupImages() {
420 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9);
421 setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2);
422 setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3);
423 setupImage(3, null, null, 0L, null, null, null, 0, 0);
426 private void setupImage(int imageNumber, String id,
427 String parentAlbumId, Long creationTime, String key, String title,
428 String description, Integer width, Integer height) {
429 final String imagePrefix = "Sone/1/Images/" + imageNumber;
430 setupString(imagePrefix + "/ID", id);
431 setupString(imagePrefix + "/Album", parentAlbumId);
432 setupLong(imagePrefix + "/CreationTime", creationTime);
433 setupString(imagePrefix + "/Key", key);
434 setupString(imagePrefix + "/Title", title);
435 setupString(imagePrefix + "/Description", description);
436 setupInteger(imagePrefix + "/Width", width);
437 setupInteger(imagePrefix + "/Height", height);
440 private ImageBuilderFactory createImageBuilderFactory() {
441 ImageBuilderFactory imageBuilderFactory =
442 mock(ImageBuilderFactory.class);
443 when(imageBuilderFactory.newImageBuilder()).thenAnswer(
444 new Answer<ImageBuilder>() {
446 public ImageBuilder answer(InvocationOnMock invocation)
448 return new TestImageBuilder();
451 return imageBuilderFactory;
454 @Test(expected = InvalidImageFound.class)
455 public void missingAlbumIdIsRecognized() {
456 setupTopLevelAlbums();
457 configurationSoneParser.parseTopLevelAlbums(
458 createAlbumBuilderFactory());
459 setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9);
460 configurationSoneParser.parseImages(createImageBuilderFactory());
463 @Test(expected = InvalidParentAlbumFound.class)
464 public void invalidAlbumIdIsRecognized() {
465 setupTopLevelAlbums();
466 configurationSoneParser.parseTopLevelAlbums(
467 createAlbumBuilderFactory());
468 setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9);
469 configurationSoneParser.parseImages(createImageBuilderFactory());
472 @Test(expected = InvalidImageFound.class)
473 public void missingCreationTimeIsRecognized() {
474 setupTopLevelAlbums();
475 configurationSoneParser.parseTopLevelAlbums(
476 createAlbumBuilderFactory());
477 setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9);
478 configurationSoneParser.parseImages(createImageBuilderFactory());
481 @Test(expected = InvalidImageFound.class)
482 public void missingKeyIsRecognized() {
483 setupTopLevelAlbums();
484 configurationSoneParser.parseTopLevelAlbums(
485 createAlbumBuilderFactory());
486 setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9);
487 configurationSoneParser.parseImages(createImageBuilderFactory());
490 @Test(expected = InvalidImageFound.class)
491 public void missingTitleIsRecognized() {
492 setupTopLevelAlbums();
493 configurationSoneParser.parseTopLevelAlbums(
494 createAlbumBuilderFactory());
495 setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9);
496 configurationSoneParser.parseImages(createImageBuilderFactory());
499 @Test(expected = InvalidImageFound.class)
500 public void missingDescriptionIsRecognized() {
501 setupTopLevelAlbums();
502 configurationSoneParser.parseTopLevelAlbums(
503 createAlbumBuilderFactory());
504 setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9);
505 configurationSoneParser.parseImages(createImageBuilderFactory());
508 @Test(expected = InvalidImageFound.class)
509 public void missingWidthIsRecognized() {
510 setupTopLevelAlbums();
511 configurationSoneParser.parseTopLevelAlbums(
512 createAlbumBuilderFactory());
513 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9);
514 configurationSoneParser.parseImages(createImageBuilderFactory());
517 @Test(expected = InvalidImageFound.class)
518 public void missingHeightIsRecognized() {
519 setupTopLevelAlbums();
520 configurationSoneParser.parseTopLevelAlbums(
521 createAlbumBuilderFactory());
522 setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null);
523 configurationSoneParser.parseImages(createImageBuilderFactory());
526 private static class TestValue<T> implements Value<T> {
528 private final AtomicReference<T> value = new AtomicReference<T>();
530 public TestValue(T originalValue) {
531 value.set(originalValue);
535 public T getValue() throws ConfigurationException {
540 public T getValue(T defaultValue) {
541 final T realValue = value.get();
542 return (realValue != null) ? realValue : defaultValue;
546 public void setValue(T newValue) throws ConfigurationException {