1 package net.pterodactylus.sone.core;
3 import static com.google.common.base.Optional.fromNullable;
4 import static com.google.common.base.Optional.of;
5 import static java.lang.System.currentTimeMillis;
6 import static java.util.UUID.randomUUID;
7 import static net.pterodactylus.sone.Matchers.isAlbum;
8 import static net.pterodactylus.sone.Matchers.isPost;
9 import static net.pterodactylus.sone.Matchers.isPostReply;
10 import static org.hamcrest.MatcherAssert.assertThat;
11 import static org.hamcrest.Matchers.contains;
12 import static org.hamcrest.Matchers.containsInAnyOrder;
13 import static org.hamcrest.Matchers.emptyIterable;
14 import static org.hamcrest.Matchers.hasSize;
15 import static org.hamcrest.Matchers.is;
16 import static org.hamcrest.Matchers.notNullValue;
17 import static org.hamcrest.Matchers.nullValue;
18 import static org.mockito.Matchers.any;
19 import static org.mockito.Matchers.anyString;
20 import static org.mockito.Matchers.eq;
21 import static org.mockito.Mockito.doAnswer;
22 import static org.mockito.Mockito.mock;
23 import static org.mockito.Mockito.when;
25 import java.util.ArrayList;
26 import java.util.Collection;
27 import java.util.List;
29 import java.util.concurrent.atomic.AtomicReference;
31 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
32 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
33 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
34 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
35 import net.pterodactylus.sone.data.Album;
36 import net.pterodactylus.sone.data.Album.Modifier;
37 import net.pterodactylus.sone.data.Image;
38 import net.pterodactylus.sone.data.Post;
39 import net.pterodactylus.sone.data.PostReply;
40 import net.pterodactylus.sone.data.Profile;
41 import net.pterodactylus.sone.data.Profile.Field;
42 import net.pterodactylus.sone.data.Sone;
43 import net.pterodactylus.sone.database.AlbumBuilder;
44 import net.pterodactylus.sone.database.AlbumBuilderFactory;
45 import net.pterodactylus.sone.database.PostBuilder;
46 import net.pterodactylus.sone.database.PostBuilderFactory;
47 import net.pterodactylus.sone.database.PostReplyBuilder;
48 import net.pterodactylus.sone.database.PostReplyBuilderFactory;
49 import net.pterodactylus.util.config.Configuration;
50 import net.pterodactylus.util.config.ConfigurationException;
51 import net.pterodactylus.util.config.Value;
53 import com.google.common.base.Optional;
54 import org.hamcrest.Matchers;
55 import org.junit.Test;
56 import org.mockito.invocation.InvocationOnMock;
57 import org.mockito.stubbing.Answer;
60 * Unit test for {@link ConfigurationSoneParser}.
62 * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
64 public class ConfigurationSoneParserTest {
66 private final Configuration configuration = mock(Configuration.class);
67 private final Sone sone = mock(Sone.class);
68 private final ConfigurationSoneParser configurationSoneParser;
70 public ConfigurationSoneParserTest() {
71 when(sone.getId()).thenReturn("1");
72 configurationSoneParser =
73 new ConfigurationSoneParser(configuration, sone);
77 public void emptyProfileIsLoadedCorrectly() {
79 Profile profile = configurationSoneParser.parseProfile();
80 assertThat(profile, notNullValue());
81 assertThat(profile.getFirstName(), nullValue());
82 assertThat(profile.getMiddleName(), nullValue());
83 assertThat(profile.getLastName(), nullValue());
84 assertThat(profile.getBirthDay(), nullValue());
85 assertThat(profile.getBirthMonth(), nullValue());
86 assertThat(profile.getBirthYear(), nullValue());
87 assertThat(profile.getFields(), emptyIterable());
90 private void setupEmptyProfile() {
91 when(configuration.getStringValue(anyString())).thenReturn(
92 new TestValue<String>(null));
93 when(configuration.getIntValue(anyString())).thenReturn(
94 new TestValue<Integer>(null));
98 public void filledProfileWithFieldsIsParsedCorrectly() {
100 Profile profile = configurationSoneParser.parseProfile();
101 assertThat(profile, notNullValue());
102 assertThat(profile.getFirstName(), is("First"));
103 assertThat(profile.getMiddleName(), is("M."));
104 assertThat(profile.getLastName(), is("Last"));
105 assertThat(profile.getBirthDay(), is(18));
106 assertThat(profile.getBirthMonth(), is(12));
107 assertThat(profile.getBirthYear(), is(1976));
108 final List<Field> fields = profile.getFields();
109 assertThat(fields, hasSize(2));
110 assertThat(fields.get(0).getName(), is("Field1"));
111 assertThat(fields.get(0).getValue(), is("Value1"));
112 assertThat(fields.get(1).getName(), is("Field2"));
113 assertThat(fields.get(1).getValue(), is("Value2"));
116 private void setupFilledProfile() {
117 setupString("Sone/1/Profile/FirstName", "First");
118 setupString("Sone/1/Profile/MiddleName", "M.");
119 setupString("Sone/1/Profile/LastName", "Last");
120 setupInteger("Sone/1/Profile/BirthDay", 18);
121 setupInteger("Sone/1/Profile/BirthMonth", 12);
122 setupInteger("Sone/1/Profile/BirthYear", 1976);
123 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
124 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
125 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
126 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
127 setupString("Sone/1/Profile/Fields/2/Name", null);
130 private void setupString(String nodeName, String value) {
131 when(configuration.getStringValue(eq(nodeName))).thenReturn(
132 new TestValue<String>(value));
135 private void setupInteger(String nodeName, Integer value) {
136 when(configuration.getIntValue(eq(nodeName))).thenReturn(
137 new TestValue<Integer>(value));
141 public void postsAreParsedCorrectly() {
142 setupCompletePosts();
143 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
144 Collection<Post> posts =
145 configurationSoneParser.parsePosts(postBuilderFactory);
147 Matchers.<Post>containsInAnyOrder(
148 isPost("P0", 1000L, "T0", Optional.<String>absent()),
149 isPost("P1", 1001L, "T1",
150 of("1234567890123456789012345678901234567890123"))));
153 private PostBuilderFactory createPostBuilderFactory() {
154 PostBuilderFactory postBuilderFactory =
155 mock(PostBuilderFactory.class);
156 when(postBuilderFactory.newPostBuilder()).thenAnswer(
157 new Answer<PostBuilder>() {
159 public PostBuilder answer(InvocationOnMock invocation)
161 return new TestPostBuilder();
164 return postBuilderFactory;
167 private void setupCompletePosts() {
168 setupPost("0", "P0", 1000L, "T0", null);
169 setupPost("1", "P1", 1001L, "T1",
170 "1234567890123456789012345678901234567890123");
171 setupPost("2", null, 0L, null, null);
174 private void setupPost(String postNumber, String postId, long time,
175 String text, String recipientId) {
176 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
177 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
178 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
179 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
182 private void setupLong(String nodeName, Long value) {
183 when(configuration.getLongValue(eq(nodeName))).thenReturn(
184 new TestValue<Long>(value));
187 @Test(expected = InvalidPostFound.class)
188 public void postWithoutTimeIsRecognized() {
189 setupPostWithoutTime();
190 configurationSoneParser.parsePosts(createPostBuilderFactory());
193 private void setupPostWithoutTime() {
194 setupPost("0", "P0", 0L, "T0", null);
197 @Test(expected = InvalidPostFound.class)
198 public void postWithoutTextIsRecognized() {
199 setupPostWithoutText();
200 configurationSoneParser.parsePosts(createPostBuilderFactory());
203 private void setupPostWithoutText() {
204 setupPost("0", "P0", 1000L, null, null);
208 public void postWithInvalidRecipientIdIsRecognized() {
209 setupPostWithInvalidRecipientId();
210 Collection<Post> posts = configurationSoneParser.parsePosts(
211 createPostBuilderFactory());
212 assertThat(posts, contains(
213 isPost("P0", 1000L, "T0", Optional.<String>absent())));
216 private void setupPostWithInvalidRecipientId() {
217 setupPost("0", "P0", 1000L, "T0", "123");
218 setupPost("1", null, 0L, null, null);
222 public void postRepliesAreParsedCorrectly() {
224 PostReplyBuilderFactory postReplyBuilderFactory =
225 new PostReplyBuilderFactory() {
227 public PostReplyBuilder newPostReplyBuilder() {
228 return new TestPostReplyBuilder();
231 Collection<PostReply> postReplies =
232 configurationSoneParser.parsePostReplies(
233 postReplyBuilderFactory);
234 assertThat(postReplies, hasSize(2));
235 assertThat(postReplies,
236 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
237 isPostReply("R1", "P1", 1001L, "T1")));
240 private void setupPostReplies() {
241 setupPostReply("0", "R0", "P0", 1000L, "T0");
242 setupPostReply("1", "R1", "P1", 1001L, "T1");
243 setupPostReply("2", null, null, 0L, null);
246 private void setupPostReply(String postReplyNumber, String postReplyId,
247 String postId, long time, String text) {
248 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
249 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
250 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
251 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
254 @Test(expected = InvalidPostReplyFound.class)
255 public void missingPostIdIsRecognized() {
256 setupPostReplyWithMissingPostId();
257 configurationSoneParser.parsePostReplies(null);
260 private void setupPostReplyWithMissingPostId() {
261 setupPostReply("0", "R0", null, 1000L, "T0");
264 @Test(expected = InvalidPostReplyFound.class)
265 public void missingPostReplyTimeIsRecognized() {
266 setupPostReplyWithMissingPostReplyTime();
267 configurationSoneParser.parsePostReplies(null);
270 private void setupPostReplyWithMissingPostReplyTime() {
271 setupPostReply("0", "R0", "P0", 0L, "T0");
274 @Test(expected = InvalidPostReplyFound.class)
275 public void missingPostReplyTextIsRecognized() {
276 setupPostReplyWithMissingPostReplyText();
277 configurationSoneParser.parsePostReplies(null);
280 private void setupPostReplyWithMissingPostReplyText() {
281 setupPostReply("0", "R0", "P0", 1000L, null);
285 public void likedPostIdsParsedCorrectly() {
287 Set<String> likedPostIds =
288 configurationSoneParser.parseLikedPostIds();
289 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
292 private void setupLikedPostIds() {
293 setupString("Sone/1/Likes/Post/0/ID", "P1");
294 setupString("Sone/1/Likes/Post/1/ID", "P2");
295 setupString("Sone/1/Likes/Post/2/ID", "P3");
296 setupString("Sone/1/Likes/Post/3/ID", null);
300 public void likedPostReplyIdsAreParsedCorrectly() {
301 setupLikedPostReplyIds();
302 Set<String> likedPostReplyIds =
303 configurationSoneParser.parseLikedPostReplyIds();
304 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
307 private void setupLikedPostReplyIds() {
308 setupString("Sone/1/Likes/Reply/0/ID", "R1");
309 setupString("Sone/1/Likes/Reply/1/ID", "R2");
310 setupString("Sone/1/Likes/Reply/2/ID", "R3");
311 setupString("Sone/1/Likes/Reply/3/ID", null);
315 public void friendsAreParsedCorrectly() {
317 Set<String> friends = configurationSoneParser.parseFriends();
318 assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
321 private void setupFriends() {
322 setupString("Sone/1/Friends/0/ID", "F1");
323 setupString("Sone/1/Friends/1/ID", "F2");
324 setupString("Sone/1/Friends/2/ID", "F3");
325 setupString("Sone/1/Friends/3/ID", null);
329 public void topLevelAlbumsAreParsedCorrectly() {
330 setupTopLevelAlbums();
331 AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
332 List<Album> topLevelAlbums =
333 configurationSoneParser.parseTopLevelAlbums(
334 albumBuilderFactory);
335 assertThat(topLevelAlbums, hasSize(2));
336 Album firstAlbum = topLevelAlbums.get(0);
337 assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1", "I1"));
338 assertThat(firstAlbum.getAlbums(), emptyIterable());
339 assertThat(firstAlbum.getImages(), emptyIterable());
340 Album secondAlbum = topLevelAlbums.get(1);
341 assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2", null));
342 assertThat(secondAlbum.getAlbums(), hasSize(1));
343 assertThat(secondAlbum.getImages(), emptyIterable());
344 Album thirdAlbum = secondAlbum.getAlbums().get(0);
345 assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3", "I3"));
346 assertThat(thirdAlbum.getAlbums(), emptyIterable());
347 assertThat(thirdAlbum.getImages(), emptyIterable());
350 private void setupTopLevelAlbums() {
351 setupAlbum(0, "A1", null, "T1", "D1", "I1");
352 setupAlbum(1, "A2", null, "T2", "D2", null);
353 setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
354 setupAlbum(3, null, null, null, null, null);
357 private void setupAlbum(int albumNumber, String albumId,
358 String parentAlbumId,
359 String title, String description, String imageId) {
360 final String albumPrefix = "Sone/1/Albums/" + albumNumber;
361 setupString(albumPrefix + "/ID", albumId);
362 setupString(albumPrefix + "/Title", title);
363 setupString(albumPrefix + "/Description", description);
364 setupString(albumPrefix + "/Parent", parentAlbumId);
365 setupString(albumPrefix + "/AlbumImage", imageId);
368 private AlbumBuilderFactory createAlbumBuilderFactory() {
369 AlbumBuilderFactory albumBuilderFactory =
370 mock(AlbumBuilderFactory.class);
371 when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
372 new Answer<AlbumBuilder>() {
374 public AlbumBuilder answer(InvocationOnMock invocation) {
375 return new TestAlbumBuilder();
378 return albumBuilderFactory;
381 @Test(expected = InvalidAlbumFound.class)
382 public void albumWithInvalidTitleIsRecognized() {
383 setupAlbum(0, "A1", null, null, "D1", "I1");
384 configurationSoneParser.parseTopLevelAlbums(
385 createAlbumBuilderFactory());
388 @Test(expected = InvalidAlbumFound.class)
389 public void albumWithInvalidDescriptionIsRecognized() {
390 setupAlbum(0, "A1", null, "T1", null, "I1");
391 configurationSoneParser.parseTopLevelAlbums(
392 createAlbumBuilderFactory());
395 @Test(expected = InvalidParentAlbumFound.class)
396 public void albumWithInvalidParentIsRecognized() {
397 setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
398 configurationSoneParser.parseTopLevelAlbums(
399 createAlbumBuilderFactory());
402 private static class TestValue<T> implements Value<T> {
404 private final AtomicReference<T> value = new AtomicReference<T>();
406 public TestValue(T originalValue) {
407 value.set(originalValue);
411 public T getValue() throws ConfigurationException {
416 public T getValue(T defaultValue) {
417 final T realValue = value.get();
418 return (realValue != null) ? realValue : defaultValue;
422 public void setValue(T newValue) throws ConfigurationException {
428 private static class TestPostBuilder implements PostBuilder {
430 private final Post post = mock(Post.class);
431 private String recipientId = null;
434 public PostBuilder copyPost(Post post) throws NullPointerException {
439 public PostBuilder from(String senderId) {
440 final Sone sone = mock(Sone.class);
441 when(sone.getId()).thenReturn(senderId);
442 when(post.getSone()).thenReturn(sone);
447 public PostBuilder randomId() {
448 when(post.getId()).thenReturn(randomUUID().toString());
453 public PostBuilder withId(String id) {
454 when(post.getId()).thenReturn(id);
459 public PostBuilder currentTime() {
460 when(post.getTime()).thenReturn(currentTimeMillis());
465 public PostBuilder withTime(long time) {
466 when(post.getTime()).thenReturn(time);
471 public PostBuilder withText(String text) {
472 when(post.getText()).thenReturn(text);
477 public PostBuilder to(String recipientId) {
478 this.recipientId = recipientId;
483 public Post build() throws IllegalStateException {
484 when(post.getRecipientId()).thenReturn(fromNullable(recipientId));
490 private static class TestPostReplyBuilder implements PostReplyBuilder {
492 private final PostReply postReply = mock(PostReply.class);
495 public PostReplyBuilder to(String postId) {
496 when(postReply.getPostId()).thenReturn(postId);
501 public PostReply build() throws IllegalStateException {
506 public PostReplyBuilder randomId() {
507 when(postReply.getId()).thenReturn(randomUUID().toString());
512 public PostReplyBuilder withId(String id) {
513 when(postReply.getId()).thenReturn(id);
518 public PostReplyBuilder from(String senderId) {
519 Sone sone = mock(Sone.class);
520 when(sone.getId()).thenReturn(senderId);
521 when(postReply.getSone()).thenReturn(sone);
526 public PostReplyBuilder currentTime() {
527 when(postReply.getTime()).thenReturn(currentTimeMillis());
532 public PostReplyBuilder withTime(long time) {
533 when(postReply.getTime()).thenReturn(time);
538 public PostReplyBuilder withText(String text) {
539 when(postReply.getText()).thenReturn(text);
545 private static class TestAlbumBuilder implements AlbumBuilder {
547 private final Album album = mock(Album.class);
548 private final List<Album> albums = new ArrayList<Album>();
549 private final List<Image> images = new ArrayList<Image>();
550 private Album parentAlbum;
551 private String title;
552 private String description;
553 private String imageId;
555 public TestAlbumBuilder() {
556 when(album.getTitle()).thenAnswer(new Answer<String>() {
558 public String answer(InvocationOnMock invocation) {
562 when(album.getDescription()).thenAnswer(new Answer<String>() {
564 public String answer(InvocationOnMock invocation) {
568 when(album.getAlbumImage()).thenAnswer(new Answer<Image>() {
570 public Image answer(InvocationOnMock invocation) {
571 if (imageId == null) {
574 Image image = mock(Image.class);
575 when(image.getId()).thenReturn(imageId);
579 when(album.getAlbums()).thenReturn(albums);
580 when(album.getImages()).thenReturn(images);
581 doAnswer(new Answer<Void>() {
583 public Void answer(InvocationOnMock invocation) {
584 albums.add((Album) invocation.getArguments()[0]);
585 ((Album) invocation.getArguments()[0]).setParent(album);
588 }).when(album).addAlbum(any(Album.class));
589 doAnswer(new Answer<Void>() {
591 public Void answer(InvocationOnMock invocation) {
592 images.add((Image) invocation.getArguments()[0]);
595 }).when(album).addImage(any(Image.class));
596 doAnswer(new Answer<Void>() {
598 public Void answer(InvocationOnMock invocation) {
599 parentAlbum = (Album) invocation.getArguments()[0];
602 }).when(album).setParent(any(Album.class));
603 when(album.getParent()).thenAnswer(new Answer<Album>() {
605 public Album answer(InvocationOnMock invocation) {
609 when(album.modify()).thenReturn(new Modifier() {
611 public Modifier setTitle(String title) {
612 TestAlbumBuilder.this.title = title;
617 public Modifier setDescription(String description) {
618 TestAlbumBuilder.this.description = description;
623 public Modifier setAlbumImage(String imageId) {
624 TestAlbumBuilder.this.imageId = imageId;
629 public Album update() throws IllegalStateException {
636 public AlbumBuilder randomId() {
637 when(album.getId()).thenReturn(randomUUID().toString());
642 public AlbumBuilder withId(String id) {
643 when(album.getId()).thenReturn(id);
648 public AlbumBuilder by(Sone sone) {
649 when(album.getSone()).thenReturn(sone);
654 public Album build() throws IllegalStateException {