Move liked post reply IDs to new configuration parser.
[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.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.isPost;
8 import static net.pterodactylus.sone.Matchers.isPostReply;
9 import static org.hamcrest.MatcherAssert.assertThat;
10 import static org.hamcrest.Matchers.contains;
11 import static org.hamcrest.Matchers.containsInAnyOrder;
12 import static org.hamcrest.Matchers.emptyIterable;
13 import static org.hamcrest.Matchers.hasSize;
14 import static org.hamcrest.Matchers.is;
15 import static org.hamcrest.Matchers.notNullValue;
16 import static org.hamcrest.Matchers.nullValue;
17 import static org.mockito.Matchers.anyString;
18 import static org.mockito.Matchers.eq;
19 import static org.mockito.Mockito.mock;
20 import static org.mockito.Mockito.when;
21
22 import java.util.Collection;
23 import java.util.List;
24 import java.util.Set;
25 import java.util.concurrent.atomic.AtomicReference;
26
27 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
28 import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
29 import net.pterodactylus.sone.data.Post;
30 import net.pterodactylus.sone.data.PostReply;
31 import net.pterodactylus.sone.data.Profile;
32 import net.pterodactylus.sone.data.Profile.Field;
33 import net.pterodactylus.sone.data.Sone;
34 import net.pterodactylus.sone.database.PostBuilder;
35 import net.pterodactylus.sone.database.PostBuilderFactory;
36 import net.pterodactylus.sone.database.PostReplyBuilder;
37 import net.pterodactylus.sone.database.PostReplyBuilderFactory;
38 import net.pterodactylus.util.config.Configuration;
39 import net.pterodactylus.util.config.ConfigurationException;
40 import net.pterodactylus.util.config.Value;
41
42 import com.google.common.base.Optional;
43 import org.hamcrest.Matchers;
44 import org.junit.Test;
45 import org.mockito.invocation.InvocationOnMock;
46 import org.mockito.stubbing.Answer;
47
48 /**
49  * Unit test for {@link ConfigurationSoneParser}.
50  *
51  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
52  */
53 public class ConfigurationSoneParserTest {
54
55         private final Configuration configuration = mock(Configuration.class);
56         private final Sone sone = mock(Sone.class);
57         private final ConfigurationSoneParser configurationSoneParser;
58
59         public ConfigurationSoneParserTest() {
60                 when(sone.getId()).thenReturn("1");
61                 configurationSoneParser =
62                                 new ConfigurationSoneParser(configuration, sone);
63         }
64
65         @Test
66         public void emptyProfileIsLoadedCorrectly() {
67                 setupEmptyProfile();
68                 Profile profile = configurationSoneParser.parseProfile();
69                 assertThat(profile, notNullValue());
70                 assertThat(profile.getFirstName(), nullValue());
71                 assertThat(profile.getMiddleName(), nullValue());
72                 assertThat(profile.getLastName(), nullValue());
73                 assertThat(profile.getBirthDay(), nullValue());
74                 assertThat(profile.getBirthMonth(), nullValue());
75                 assertThat(profile.getBirthYear(), nullValue());
76                 assertThat(profile.getFields(), emptyIterable());
77         }
78
79         private void setupEmptyProfile() {
80                 when(configuration.getStringValue(anyString())).thenReturn(
81                                 new TestValue<String>(null));
82                 when(configuration.getIntValue(anyString())).thenReturn(
83                                 new TestValue<Integer>(null));
84         }
85
86         @Test
87         public void filledProfileWithFieldsIsParsedCorrectly() {
88                 setupFilledProfile();
89                 Profile profile = configurationSoneParser.parseProfile();
90                 assertThat(profile, notNullValue());
91                 assertThat(profile.getFirstName(), is("First"));
92                 assertThat(profile.getMiddleName(), is("M."));
93                 assertThat(profile.getLastName(), is("Last"));
94                 assertThat(profile.getBirthDay(), is(18));
95                 assertThat(profile.getBirthMonth(), is(12));
96                 assertThat(profile.getBirthYear(), is(1976));
97                 final List<Field> fields = profile.getFields();
98                 assertThat(fields, hasSize(2));
99                 assertThat(fields.get(0).getName(), is("Field1"));
100                 assertThat(fields.get(0).getValue(), is("Value1"));
101                 assertThat(fields.get(1).getName(), is("Field2"));
102                 assertThat(fields.get(1).getValue(), is("Value2"));
103         }
104
105         private void setupFilledProfile() {
106                 setupString("Sone/1/Profile/FirstName", "First");
107                 setupString("Sone/1/Profile/MiddleName", "M.");
108                 setupString("Sone/1/Profile/LastName", "Last");
109                 setupInteger("Sone/1/Profile/BirthDay", 18);
110                 setupInteger("Sone/1/Profile/BirthMonth", 12);
111                 setupInteger("Sone/1/Profile/BirthYear", 1976);
112                 setupString("Sone/1/Profile/Fields/0/Name", "Field1");
113                 setupString("Sone/1/Profile/Fields/0/Value", "Value1");
114                 setupString("Sone/1/Profile/Fields/1/Name", "Field2");
115                 setupString("Sone/1/Profile/Fields/1/Value", "Value2");
116                 setupString("Sone/1/Profile/Fields/2/Name", null);
117         }
118
119         private void setupString(String nodeName, String value) {
120                 when(configuration.getStringValue(eq(nodeName))).thenReturn(
121                                 new TestValue<String>(value));
122         }
123
124         private void setupInteger(String nodeName, Integer value) {
125                 when(configuration.getIntValue(eq(nodeName))).thenReturn(
126                                 new TestValue<Integer>(value));
127         }
128
129         @Test
130         public void postsAreParsedCorrectly() {
131                 setupCompletePosts();
132                 PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
133                 Collection<Post> posts =
134                                 configurationSoneParser.parsePosts(postBuilderFactory);
135                 assertThat(posts,
136                                 Matchers.<Post>containsInAnyOrder(
137                                                 isPost("P0", 1000L, "T0", Optional.<String>absent()),
138                                                 isPost("P1", 1001L, "T1",
139                                                                 of("1234567890123456789012345678901234567890123"))));
140         }
141
142         private PostBuilderFactory createPostBuilderFactory() {
143                 PostBuilderFactory postBuilderFactory =
144                                 mock(PostBuilderFactory.class);
145                 when(postBuilderFactory.newPostBuilder()).thenAnswer(
146                                 new Answer<PostBuilder>() {
147                                         @Override
148                                         public PostBuilder answer(InvocationOnMock invocation)
149                                         throws Throwable {
150                                                 return new TestPostBuilder();
151                                         }
152                                 });
153                 return postBuilderFactory;
154         }
155
156         private void setupCompletePosts() {
157                 setupPost("0", "P0", 1000L, "T0", null);
158                 setupPost("1", "P1", 1001L, "T1",
159                                 "1234567890123456789012345678901234567890123");
160                 setupPost("2", null, 0L, null, null);
161         }
162
163         private void setupPost(String postNumber, String postId, long time,
164                         String text, String recipientId) {
165                 setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
166                 setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
167                 setupString("Sone/1/Posts/" + postNumber + "/Text", text);
168                 setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
169         }
170
171         private void setupLong(String nodeName, Long value) {
172                 when(configuration.getLongValue(eq(nodeName))).thenReturn(
173                                 new TestValue<Long>(value));
174         }
175
176         @Test(expected = InvalidPostFound.class)
177         public void postWithoutTimeIsRecognized() {
178                 setupPostWithoutTime();
179                 configurationSoneParser.parsePosts(createPostBuilderFactory());
180         }
181
182         private void setupPostWithoutTime() {
183                 setupPost("0", "P0", 0L, "T0", null);
184         }
185
186         @Test(expected = InvalidPostFound.class)
187         public void postWithoutTextIsRecognized() {
188                 setupPostWithoutText();
189                 configurationSoneParser.parsePosts(createPostBuilderFactory());
190         }
191
192         private void setupPostWithoutText() {
193                 setupPost("0", "P0", 1000L, null, null);
194         }
195
196         @Test
197         public void postWithInvalidRecipientIdIsRecognized() {
198                 setupPostWithInvalidRecipientId();
199                 Collection<Post> posts = configurationSoneParser.parsePosts(
200                                 createPostBuilderFactory());
201                 assertThat(posts, contains(
202                                 isPost("P0", 1000L, "T0", Optional.<String>absent())));
203         }
204
205         private void setupPostWithInvalidRecipientId() {
206                 setupPost("0", "P0", 1000L, "T0", "123");
207                 setupPost("1", null, 0L, null, null);
208         }
209
210         @Test
211         public void postRepliesAreParsedCorrectly() {
212                 setupPostReplies();
213                 PostReplyBuilderFactory postReplyBuilderFactory =
214                                 new PostReplyBuilderFactory() {
215                                         @Override
216                                         public PostReplyBuilder newPostReplyBuilder() {
217                                                 return new TestPostReplyBuilder();
218                                         }
219                                 };
220                 Collection<PostReply> postReplies =
221                                 configurationSoneParser.parsePostReplies(
222                                                 postReplyBuilderFactory);
223                 assertThat(postReplies, hasSize(2));
224                 assertThat(postReplies,
225                                 containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
226                                                 isPostReply("R1", "P1", 1001L, "T1")));
227         }
228
229         private void setupPostReplies() {
230                 setupPostReply("0", "R0", "P0", 1000L, "T0");
231                 setupPostReply("1", "R1", "P1", 1001L, "T1");
232                 setupPostReply("2", null, null, 0L, null);
233         }
234
235         private void setupPostReply(String postReplyNumber, String postReplyId,
236                         String postId, long time, String text) {
237                 setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
238                 setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
239                 setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
240                 setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
241         }
242
243         @Test(expected = InvalidPostReplyFound.class)
244         public void missingPostIdIsRecognized() {
245                 setupPostReplyWithMissingPostId();
246                 configurationSoneParser.parsePostReplies(null);
247         }
248
249         private void setupPostReplyWithMissingPostId() {
250                 setupPostReply("0", "R0", null, 1000L, "T0");
251         }
252
253         @Test(expected = InvalidPostReplyFound.class)
254         public void missingPostReplyTimeIsRecognized() {
255                 setupPostReplyWithMissingPostReplyTime();
256                 configurationSoneParser.parsePostReplies(null);
257         }
258
259         private void setupPostReplyWithMissingPostReplyTime() {
260                 setupPostReply("0", "R0", "P0", 0L, "T0");
261         }
262
263         @Test(expected = InvalidPostReplyFound.class)
264         public void missingPostReplyTextIsRecognized() {
265                 setupPostReplyWithMissingPostReplyText();
266                 configurationSoneParser.parsePostReplies(null);
267         }
268
269         private void setupPostReplyWithMissingPostReplyText() {
270                 setupPostReply("0", "R0", "P0", 1000L, null);
271         }
272
273         @Test
274         public void likedPostIdsParsedCorrectly() {
275                 setupLikedPostIds();
276                 Set<String> likedPostIds =
277                                 configurationSoneParser.parseLikedPostIds();
278                 assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
279         }
280
281         private void setupLikedPostIds() {
282                 setupString("Sone/1/Likes/Post/0/ID", "P1");
283                 setupString("Sone/1/Likes/Post/1/ID", "P2");
284                 setupString("Sone/1/Likes/Post/2/ID", "P3");
285                 setupString("Sone/1/Likes/Post/3/ID", null);
286         }
287
288         @Test
289         public void likedPostReplyIdsAreParsedCorrectly() {
290                 setupLikedPostReplyIds();
291                 Set<String> likedPostReplyIds =
292                                 configurationSoneParser.parseLikedPostReplyIds();
293                 assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
294         }
295
296         private void setupLikedPostReplyIds() {
297                 setupString("Sone/1/Likes/Reply/0/ID", "R1");
298                 setupString("Sone/1/Likes/Reply/1/ID", "R2");
299                 setupString("Sone/1/Likes/Reply/2/ID", "R3");
300                 setupString("Sone/1/Likes/Reply/3/ID", null);
301         }
302
303         private static class TestValue<T> implements Value<T> {
304
305                 private final AtomicReference<T> value = new AtomicReference<T>();
306
307                 public TestValue(T originalValue) {
308                         value.set(originalValue);
309                 }
310
311                 @Override
312                 public T getValue() throws ConfigurationException {
313                         return value.get();
314                 }
315
316                 @Override
317                 public T getValue(T defaultValue) {
318                         final T realValue = value.get();
319                         return (realValue != null) ? realValue : defaultValue;
320                 }
321
322                 @Override
323                 public void setValue(T newValue) throws ConfigurationException {
324                         value.set(newValue);
325                 }
326
327         }
328
329         private static class TestPostBuilder implements PostBuilder {
330
331                 private final Post post = mock(Post.class);
332                 private String recipientId = null;
333
334                 @Override
335                 public PostBuilder copyPost(Post post) throws NullPointerException {
336                         return this;
337                 }
338
339                 @Override
340                 public PostBuilder from(String senderId) {
341                         final Sone sone = mock(Sone.class);
342                         when(sone.getId()).thenReturn(senderId);
343                         when(post.getSone()).thenReturn(sone);
344                         return this;
345                 }
346
347                 @Override
348                 public PostBuilder randomId() {
349                         when(post.getId()).thenReturn(randomUUID().toString());
350                         return this;
351                 }
352
353                 @Override
354                 public PostBuilder withId(String id) {
355                         when(post.getId()).thenReturn(id);
356                         return this;
357                 }
358
359                 @Override
360                 public PostBuilder currentTime() {
361                         when(post.getTime()).thenReturn(currentTimeMillis());
362                         return this;
363                 }
364
365                 @Override
366                 public PostBuilder withTime(long time) {
367                         when(post.getTime()).thenReturn(time);
368                         return this;
369                 }
370
371                 @Override
372                 public PostBuilder withText(String text) {
373                         when(post.getText()).thenReturn(text);
374                         return this;
375                 }
376
377                 @Override
378                 public PostBuilder to(String recipientId) {
379                         this.recipientId = recipientId;
380                         return this;
381                 }
382
383                 @Override
384                 public Post build() throws IllegalStateException {
385                         when(post.getRecipientId()).thenReturn(fromNullable(recipientId));
386                         return post;
387                 }
388
389         }
390
391         private static class TestPostReplyBuilder implements PostReplyBuilder {
392
393                 private final PostReply postReply = mock(PostReply.class);
394
395                 @Override
396                 public PostReplyBuilder to(String postId) {
397                         when(postReply.getPostId()).thenReturn(postId);
398                         return this;
399                 }
400
401                 @Override
402                 public PostReply build() throws IllegalStateException {
403                         return postReply;
404                 }
405
406                 @Override
407                 public PostReplyBuilder randomId() {
408                         when(postReply.getId()).thenReturn(randomUUID().toString());
409                         return this;
410                 }
411
412                 @Override
413                 public PostReplyBuilder withId(String id) {
414                         when(postReply.getId()).thenReturn(id);
415                         return this;
416                 }
417
418                 @Override
419                 public PostReplyBuilder from(String senderId) {
420                         Sone sone = mock(Sone.class);
421                         when(sone.getId()).thenReturn(senderId);
422                         when(postReply.getSone()).thenReturn(sone);
423                         return this;
424                 }
425
426                 @Override
427                 public PostReplyBuilder currentTime() {
428                         when(postReply.getTime()).thenReturn(currentTimeMillis());
429                         return this;
430                 }
431
432                 @Override
433                 public PostReplyBuilder withTime(long time) {
434                         when(postReply.getTime()).thenReturn(time);
435                         return this;
436                 }
437
438                 @Override
439                 public PostReplyBuilder withText(String text) {
440                         when(postReply.getText()).thenReturn(text);
441                         return this;
442                 }
443
444         }
445
446 }