Move liked post IDs parsing 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         private static class TestValue<T> implements Value<T> {
289
290                 private final AtomicReference<T> value = new AtomicReference<T>();
291
292                 public TestValue(T originalValue) {
293                         value.set(originalValue);
294                 }
295
296                 @Override
297                 public T getValue() throws ConfigurationException {
298                         return value.get();
299                 }
300
301                 @Override
302                 public T getValue(T defaultValue) {
303                         final T realValue = value.get();
304                         return (realValue != null) ? realValue : defaultValue;
305                 }
306
307                 @Override
308                 public void setValue(T newValue) throws ConfigurationException {
309                         value.set(newValue);
310                 }
311
312         }
313
314         private static class TestPostBuilder implements PostBuilder {
315
316                 private final Post post = mock(Post.class);
317                 private String recipientId = null;
318
319                 @Override
320                 public PostBuilder copyPost(Post post) throws NullPointerException {
321                         return this;
322                 }
323
324                 @Override
325                 public PostBuilder from(String senderId) {
326                         final Sone sone = mock(Sone.class);
327                         when(sone.getId()).thenReturn(senderId);
328                         when(post.getSone()).thenReturn(sone);
329                         return this;
330                 }
331
332                 @Override
333                 public PostBuilder randomId() {
334                         when(post.getId()).thenReturn(randomUUID().toString());
335                         return this;
336                 }
337
338                 @Override
339                 public PostBuilder withId(String id) {
340                         when(post.getId()).thenReturn(id);
341                         return this;
342                 }
343
344                 @Override
345                 public PostBuilder currentTime() {
346                         when(post.getTime()).thenReturn(currentTimeMillis());
347                         return this;
348                 }
349
350                 @Override
351                 public PostBuilder withTime(long time) {
352                         when(post.getTime()).thenReturn(time);
353                         return this;
354                 }
355
356                 @Override
357                 public PostBuilder withText(String text) {
358                         when(post.getText()).thenReturn(text);
359                         return this;
360                 }
361
362                 @Override
363                 public PostBuilder to(String recipientId) {
364                         this.recipientId = recipientId;
365                         return this;
366                 }
367
368                 @Override
369                 public Post build() throws IllegalStateException {
370                         when(post.getRecipientId()).thenReturn(fromNullable(recipientId));
371                         return post;
372                 }
373
374         }
375
376         private static class TestPostReplyBuilder implements PostReplyBuilder {
377
378                 private final PostReply postReply = mock(PostReply.class);
379
380                 @Override
381                 public PostReplyBuilder to(String postId) {
382                         when(postReply.getPostId()).thenReturn(postId);
383                         return this;
384                 }
385
386                 @Override
387                 public PostReply build() throws IllegalStateException {
388                         return postReply;
389                 }
390
391                 @Override
392                 public PostReplyBuilder randomId() {
393                         when(postReply.getId()).thenReturn(randomUUID().toString());
394                         return this;
395                 }
396
397                 @Override
398                 public PostReplyBuilder withId(String id) {
399                         when(postReply.getId()).thenReturn(id);
400                         return this;
401                 }
402
403                 @Override
404                 public PostReplyBuilder from(String senderId) {
405                         Sone sone = mock(Sone.class);
406                         when(sone.getId()).thenReturn(senderId);
407                         when(postReply.getSone()).thenReturn(sone);
408                         return this;
409                 }
410
411                 @Override
412                 public PostReplyBuilder currentTime() {
413                         when(postReply.getTime()).thenReturn(currentTimeMillis());
414                         return this;
415                 }
416
417                 @Override
418                 public PostReplyBuilder withTime(long time) {
419                         when(postReply.getTime()).thenReturn(time);
420                         return this;
421                 }
422
423                 @Override
424                 public PostReplyBuilder withText(String text) {
425                         when(postReply.getText()).thenReturn(text);
426                         return this;
427                 }
428
429         }
430
431 }