Merge branch 'release-0.9.4'
[Sone.git] / src / test / java / net / pterodactylus / sone / core / SoneParserTest.java
1 package net.pterodactylus.sone.core;
2
3 import static com.google.common.base.Optional.of;
4 import static freenet.keys.InsertableClientSSK.createRandom;
5 import static java.lang.System.currentTimeMillis;
6 import static java.util.UUID.randomUUID;
7 import static java.util.concurrent.TimeUnit.DAYS;
8 import static org.hamcrest.MatcherAssert.assertThat;
9 import static org.hamcrest.Matchers.hasSize;
10 import static org.hamcrest.Matchers.is;
11 import static org.hamcrest.Matchers.not;
12 import static org.hamcrest.Matchers.notNullValue;
13 import static org.hamcrest.Matchers.nullValue;
14 import static org.mockito.Matchers.any;
15 import static org.mockito.Matchers.anyLong;
16 import static org.mockito.Matchers.anyString;
17 import static org.mockito.Mockito.doAnswer;
18 import static org.mockito.Mockito.mock;
19 import static org.mockito.Mockito.when;
20
21 import java.io.InputStream;
22 import java.net.MalformedURLException;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.HashSet;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Set;
29
30 import net.pterodactylus.sone.data.Album;
31 import net.pterodactylus.sone.data.Album.Modifier;
32 import net.pterodactylus.sone.data.Client;
33 import net.pterodactylus.sone.data.Image;
34 import net.pterodactylus.sone.data.Post;
35 import net.pterodactylus.sone.data.PostReply;
36 import net.pterodactylus.sone.data.Profile;
37 import net.pterodactylus.sone.data.Sone;
38 import net.pterodactylus.sone.database.AlbumBuilder;
39 import net.pterodactylus.sone.database.ImageBuilder;
40 import net.pterodactylus.sone.database.PostBuilder;
41 import net.pterodactylus.sone.database.PostReplyBuilder;
42 import net.pterodactylus.sone.database.SoneBuilder;
43 import net.pterodactylus.sone.database.memory.MemorySoneBuilder;
44 import net.pterodactylus.sone.freenet.wot.Identity;
45 import net.pterodactylus.sone.freenet.wot.OwnIdentity;
46
47 import freenet.crypt.DummyRandomSource;
48 import freenet.keys.FreenetURI;
49 import freenet.keys.InsertableClientSSK;
50
51 import com.google.common.base.Optional;
52 import com.google.common.collect.ArrayListMultimap;
53 import com.google.common.collect.ImmutableSet;
54 import com.google.common.collect.ListMultimap;
55 import org.junit.Before;
56 import org.junit.Test;
57 import org.mockito.invocation.InvocationOnMock;
58 import org.mockito.stubbing.Answer;
59
60 /**
61  * Unit test for {@link SoneParser}.
62  *
63  * @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
64  */
65 public class SoneParserTest {
66
67         private final Core core = mock(Core.class);
68         private final SoneParser soneParser = new SoneParser(core);
69         private final Sone sone = mock(Sone.class);
70         private FreenetURI requestUri = mock(FreenetURI.class);
71         private final PostBuilder postBuilder = mock(PostBuilder.class);
72         private final List<Post> createdPosts = new ArrayList<Post>();
73         private Post post = mock(Post.class);
74         private final PostReplyBuilder postReplyBuilder = mock(PostReplyBuilder.class);
75         private final Set<PostReply> createdPostReplies = new HashSet<PostReply>();
76         private PostReply postReply = mock(PostReply.class);
77         private final AlbumBuilder albumBuilder = mock(AlbumBuilder.class);
78         private final ListMultimap<Album, Album>
79                         nestedAlbums = ArrayListMultimap.create();
80         private final ListMultimap<Album, Image> albumImages = ArrayListMultimap.create();
81         private Album album = mock(Album.class);
82         private final Map<String, Album> albums = new HashMap<String, Album>();
83         private final ImageBuilder imageBuilder = mock(ImageBuilder.class);
84         private Image image = mock(Image.class);
85         private final Map<String, Image> images = new HashMap<String, Image>();
86
87         @Before
88         public void setupSone() {
89                 setupSone(this.sone, Identity.class);
90         }
91
92         private void setupSone(Sone sone, Class<? extends Identity> identityClass) {
93                 Identity identity = mock(identityClass);
94                 InsertableClientSSK clientSSK =
95                                 createRandom(new DummyRandomSource(), "WoT");
96                 when(identity.getRequestUri()).thenReturn(clientSSK.getURI().toString());
97                 when(identity.getId()).thenReturn("identity");
98                 when(sone.getId()).thenReturn("identity");
99                 when(sone.getIdentity()).thenReturn(identity);
100                 requestUri = clientSSK.getURI().setKeyType("USK").setDocName("Sone");
101                 when(sone.getRequestUri()).thenAnswer(new Answer<FreenetURI>() {
102                         @Override
103                         public FreenetURI answer(InvocationOnMock invocation)
104                         throws Throwable {
105                                 return requestUri;
106                         }
107                 });
108                 when(sone.getTime())
109                                 .thenReturn(currentTimeMillis() - DAYS.toMillis(1));
110         }
111
112         @Before
113         public void setupSoneBuilder() {
114                 when(core.soneBuilder()).thenAnswer(new Answer<SoneBuilder>() {
115                         @Override
116                         public SoneBuilder answer(InvocationOnMock invocation) {
117                                 return new MemorySoneBuilder(null);
118                         }
119                 });
120         }
121
122         @Before
123         public void setupPost() {
124                 when(post.getRecipientId()).thenReturn(Optional.<String>absent());
125         }
126
127         @Before
128         public void setupPostBuilder() {
129                 when(postBuilder.withId(anyString())).thenAnswer(new Answer<PostBuilder>() {
130                         @Override
131                         public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
132                                 when(post.getId()).thenReturn((String) invocation.getArguments()[0]);
133                                 return postBuilder;
134                         }
135                 });
136                 when(postBuilder.from(anyString())).thenAnswer(new Answer<PostBuilder>() {
137                         @Override
138                         public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
139                                 final Sone sone = mock(Sone.class);
140                                 when(sone.getId()).thenReturn((String) invocation.getArguments()[0]);
141                                 when(post.getSone()).thenReturn(sone);
142                                 return postBuilder;
143                         }
144                 });
145                 when(postBuilder.withTime(anyLong())).thenAnswer(new Answer<PostBuilder>() {
146                         @Override
147                         public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
148                                 when(post.getTime()).thenReturn((Long) invocation.getArguments()[0]);
149                                 return postBuilder;
150                         }
151                 });
152                 when(postBuilder.withText(anyString())).thenAnswer(new Answer<PostBuilder>() {
153                         @Override
154                         public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
155                                 when(post.getText()).thenReturn((String) invocation.getArguments()[0]);
156                                 return postBuilder;
157                         }
158                 });
159                 when(postBuilder.to(anyString())).thenAnswer(new Answer<PostBuilder>() {
160                         @Override
161                         public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
162                                 when(post.getRecipientId()).thenReturn(of((String) invocation.getArguments()[0]));
163                                 return postBuilder;
164                         }
165                 });
166                 when(postBuilder.build()).thenAnswer(new Answer<Post>() {
167                         @Override
168                         public Post answer(InvocationOnMock invocation) throws Throwable {
169                                 Post post = SoneParserTest.this.post;
170                                 SoneParserTest.this.post = mock(Post.class);
171                                 setupPost();
172                                 createdPosts.add(post);
173                                 return post;
174                         }
175                 });
176                 when(core.postBuilder()).thenReturn(postBuilder);
177         }
178
179         @Before
180         public void setupPostReplyBuilder() {
181                 when(postReplyBuilder.withId(anyString())).thenAnswer(new Answer<PostReplyBuilder>() {
182                         @Override
183                         public PostReplyBuilder answer(InvocationOnMock invocation) throws Throwable {
184                                 when(postReply.getId()).thenReturn((String) invocation.getArguments()[0]);
185                                 return postReplyBuilder;
186                         }
187                 });
188                 when(postReplyBuilder.from(anyString())).thenAnswer(
189                                 new Answer<PostReplyBuilder>() {
190                                         @Override
191                                         public PostReplyBuilder answer(
192                                                         InvocationOnMock invocation) throws Throwable {
193                                                 Sone sone = when(mock(Sone.class).getId()).thenReturn(
194                                                                 (String) invocation.getArguments()[0])
195                                                                 .getMock();
196                                                 when(postReply.getSone()).thenReturn(sone);
197                                                 return postReplyBuilder;
198                                         }
199                                 });
200                 when(postReplyBuilder.to(anyString())).thenAnswer(
201                                 new Answer<PostReplyBuilder>() {
202                                         @Override
203                                         public PostReplyBuilder answer(
204                                                         InvocationOnMock invocation) throws Throwable {
205                                                 when(postReply.getPostId()).thenReturn(
206                                                                 (String) invocation.getArguments()[0]);
207                                                 Post post = when(mock(Post.class).getId()).thenReturn(
208                                                                 (String) invocation.getArguments()[0])
209                                                                 .getMock();
210                                                 when(postReply.getPost()).thenReturn(of(post));
211                                                 return postReplyBuilder;
212                                         }
213                                 });
214                 when(postReplyBuilder.withTime(anyLong())).thenAnswer(
215                                 new Answer<PostReplyBuilder>() {
216                                         @Override
217                                         public PostReplyBuilder answer(
218                                                         InvocationOnMock invocation) throws Throwable {
219                                                 when(postReply.getTime()).thenReturn(
220                                                                 (Long) invocation.getArguments()[0]);
221                                                 return postReplyBuilder;
222                                         }
223                                 });
224                 when(postReplyBuilder.withText(anyString())).thenAnswer(new Answer<PostReplyBuilder>() {
225                         @Override
226                         public PostReplyBuilder answer(InvocationOnMock invocation) throws Throwable {
227                                 when(postReply.getText()).thenReturn((String) invocation.getArguments()[0]);
228                                 return postReplyBuilder;
229                         }
230                 });
231                 when(postReplyBuilder.build()).thenAnswer(new Answer<PostReply>() {
232                         @Override
233                         public PostReply answer(InvocationOnMock invocation) throws Throwable {
234                                 PostReply postReply = SoneParserTest.this.postReply;
235                                 createdPostReplies.add(postReply);
236                                 SoneParserTest.this.postReply = mock(PostReply.class);
237                                 return postReply;
238                         }
239                 });
240                 when(core.postReplyBuilder()).thenReturn(postReplyBuilder);
241         }
242
243         @Before
244         public void setupAlbum() {
245                 final Album album = SoneParserTest.this.album;
246                 when(album.getAlbumImage()).thenReturn(mock(Image.class));
247                 doAnswer(new Answer<Void>() {
248                         @Override
249                         public Void answer(InvocationOnMock invocation) {
250                                 nestedAlbums.put(album, (Album) invocation.getArguments()[0]);
251                                 return null;
252                         }
253                 }).when(album).addAlbum(any(Album.class));
254                 doAnswer(new Answer<Void>() {
255                         @Override
256                         public Void answer(InvocationOnMock invocation) {
257                                 albumImages.put(album, (Image) invocation.getArguments()[0]);
258                                 return null;
259                         }
260                 }).when(album).addImage(any(Image.class));
261                 when(album.getAlbums()).thenAnswer(new Answer<List<Album>>() {
262                         @Override
263                         public List<Album> answer(InvocationOnMock invocation) {
264                                 return nestedAlbums.get(album);
265                         }
266                 });
267                 when(album.getImages()).thenAnswer(new Answer<List<Image>>() {
268                         @Override
269                         public List<Image> answer(InvocationOnMock invocation) {
270                                 return albumImages.get(album);
271                         }
272                 });
273                 final Modifier albumModifier = new Modifier() {
274                         private String title = album.getTitle();
275                         private String description = album.getDescription();
276                         private String imageId = album.getAlbumImage().getId();
277
278                         @Override
279                         public Modifier setTitle(String title) {
280                                 this.title = title;
281                                 return this;
282                         }
283
284                         @Override
285                         public Modifier setDescription(String description) {
286                                 this.description = description;
287                                 return this;
288                         }
289
290                         @Override
291                         public Modifier setAlbumImage(String imageId) {
292                                 this.imageId = imageId;
293                                 return this;
294                         }
295
296                         @Override
297                         public Album update() throws IllegalStateException {
298                                 when(album.getTitle()).thenReturn(title);
299                                 when(album.getDescription()).thenReturn(description);
300                                 Image image = mock(Image.class);
301                                 when(image.getId()).thenReturn(imageId);
302                                 when(album.getAlbumImage()).thenReturn(image);
303                                 return album;
304                         }
305                 };
306                 when(album.modify()).thenReturn(albumModifier);
307         }
308
309         @Before
310         public void setupAlbumBuilder() {
311                 when(albumBuilder.withId(anyString())).thenAnswer(new Answer<AlbumBuilder>() {
312                         @Override
313                         public AlbumBuilder answer(InvocationOnMock invocation) {
314                                 when(album.getId()).thenReturn((String) invocation.getArguments()[0]);
315                                 return albumBuilder;
316                         }
317                 });
318                 when(albumBuilder.randomId()).thenAnswer(new Answer<AlbumBuilder>() {
319                         @Override
320                         public AlbumBuilder answer(InvocationOnMock invocation) {
321                                 when(album.getId()).thenReturn(randomUUID().toString());
322                                 return albumBuilder;
323                         }
324                 });
325                 when(albumBuilder.by(any(Sone.class))).thenAnswer(new Answer<AlbumBuilder>() {
326                         @Override
327                         public AlbumBuilder answer(InvocationOnMock invocation) {
328                                 when(album.getSone()).thenReturn((Sone) invocation.getArguments()[0]);
329                                 return albumBuilder;
330                         }
331                 });
332                 when(albumBuilder.build()).thenAnswer(new Answer<Album>() {
333                         @Override
334                         public Album answer(InvocationOnMock invocation) {
335                                 Album album = SoneParserTest.this.album;
336                                 albums.put(album.getId(), album);
337                                 SoneParserTest.this.album = mock(Album.class);
338                                 setupAlbum();
339                                 return album;
340                         }
341                 });
342                 when(core.albumBuilder()).thenReturn(albumBuilder);
343         }
344
345         @Before
346         public void setupAlbums() {
347                 when(core.getAlbum(anyString())).thenAnswer(new Answer<Album>() {
348                         @Override
349                         public Album answer(InvocationOnMock invocation)
350                         throws Throwable {
351                                 return albums.get(invocation.getArguments()[0]);
352                         }
353                 });
354         }
355
356         @Before
357         public void setupImage() {
358                 final Image image = SoneParserTest.this.image;
359                 Image.Modifier modifier = new Image.Modifier() {
360                         private Sone sone = image.getSone();
361                         private long creationTime = image.getCreationTime();
362                         private String key = image.getKey();
363                         private String title = image.getTitle();
364                         private String description = image.getDescription();
365                         private int width = image.getWidth();
366                         private int height = image.getHeight();
367
368                         @Override
369                         public Image.Modifier setSone(Sone sone) {
370                                 this.sone = sone;
371                                 return this;
372                         }
373
374                         @Override
375                         public Image.Modifier setCreationTime(long creationTime) {
376                                 this.creationTime = creationTime;
377                                 return this;
378                         }
379
380                         @Override
381                         public Image.Modifier setKey(String key) {
382                                 this.key = key;
383                                 return this;
384                         }
385
386                         @Override
387                         public Image.Modifier setTitle(String title) {
388                                 this.title = title;
389                                 return this;
390                         }
391
392                         @Override
393                         public Image.Modifier setDescription(String description) {
394                                 this.description = description;
395                                 return this;
396                         }
397
398                         @Override
399                         public Image.Modifier setWidth(int width) {
400                                 this.width = width;
401                                 return this;
402                         }
403
404                         @Override
405                         public Image.Modifier setHeight(int height) {
406                                 this.height = height;
407                                 return this;
408                         }
409
410                         @Override
411                         public Image update() throws IllegalStateException {
412                                 when(image.getSone()).thenReturn(sone);
413                                 when(image.getCreationTime()).thenReturn(creationTime);
414                                 when(image.getKey()).thenReturn(key);
415                                 when(image.getTitle()).thenReturn(title);
416                                 when(image.getDescription()).thenReturn(description);
417                                 when(image.getWidth()).thenReturn(width);
418                                 when(image.getHeight()).thenReturn(height);
419                                 return image;
420                         }
421                 };
422                 when(image.getSone()).thenReturn(sone);
423                 when(image.modify()).thenReturn(modifier);
424         }
425
426         @Before
427         public void setupImageBuilder() {
428                 when(imageBuilder.randomId()).thenAnswer(new Answer<ImageBuilder>() {
429                         @Override
430                         public ImageBuilder answer(InvocationOnMock invocation) {
431                                 when(image.getId()).thenReturn(randomUUID().toString());
432                                 return imageBuilder;
433                         }
434                 });
435                 when(imageBuilder.withId(anyString())).thenAnswer(new Answer<ImageBuilder>() {
436                         @Override
437                         public ImageBuilder answer(InvocationOnMock invocation) {
438                                 when(image.getId()).thenReturn(
439                                                 (String) invocation.getArguments()[0]);
440                                 return imageBuilder;
441                         }
442                 });
443                 when(imageBuilder.build()).thenAnswer(new Answer<Image>() {
444                         @Override
445                         public Image answer(InvocationOnMock invocation) {
446                                 Image image = SoneParserTest.this.image;
447                                 images.put(image.getId(), image);
448                                 SoneParserTest.this.image = mock(Image.class);
449                                 setupImage();
450                                 return image;
451                         }
452                 });
453                 when(core.imageBuilder()).thenReturn(imageBuilder);
454         }
455
456         @Before
457         public void setupImages() {
458                 when(core.getImage(anyString())).thenAnswer(new Answer<Image>() {
459                         @Override
460                         public Image answer(InvocationOnMock invocation)
461                         throws Throwable {
462                                 return images.get(invocation.getArguments()[0]);
463                         }
464                 });
465         }
466         @Test
467         public void parsingASoneFailsWhenDocumentIsNotXml() throws SoneException {
468                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-not-xml.xml");
469                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
470         }
471
472         @Test
473         public void parsingASoneFailsWhenDocumentHasNegativeProtocolVersion() throws SoneException {
474                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-negative-protocol-version.xml");
475                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
476         }
477
478         @Test
479         public void parsingASoneFailsWhenProtocolVersionIsTooLarge() throws SoneException {
480                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-too-large-protocol-version.xml");
481                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
482         }
483
484         @Test
485         public void parsingASoneFailsWhenThereIsNoTime() throws SoneException {
486                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-time.xml");
487                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
488         }
489
490         @Test
491         public void parsingASoneFailsWhenTimeIsNotNumeric() throws SoneException {
492                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-time-not-numeric.xml");
493                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
494         }
495
496         @Test
497         public void parsingASoneFailsWhenProfileIsMissing() throws SoneException {
498                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-profile.xml");
499                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
500         }
501
502         @Test
503         public void parsingASoneFailsWhenProfileFieldIsMissingAFieldName() throws SoneException {
504                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-missing-field-name.xml");
505                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
506         }
507
508         @Test
509         public void parsingASoneFailsWhenProfileFieldNameIsEmpty() throws SoneException {
510                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-empty-field-name.xml");
511                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
512         }
513
514         @Test
515         public void parsingASoneFailsWhenProfileFieldNameIsNotUnique() throws SoneException {
516                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-duplicate-field-name.xml");
517                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
518         }
519
520         @Test
521         public void parsingASoneSucceedsWithoutPayload() throws SoneException {
522                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-payload.xml");
523                 assertThat(soneParser.parseSone(sone, inputStream).getTime(), is(
524                                 1407197508000L));
525         }
526
527         @Test
528         public void parsingALocalSoneSucceedsWithoutPayload() throws SoneException {
529                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-payload.xml");
530                 Sone localSone = mock(Sone.class);
531                 setupSone(localSone, OwnIdentity.class);
532                 when(localSone.isLocal()).thenReturn(true);
533                 Sone parsedSone = soneParser.parseSone(localSone, inputStream);
534                 assertThat(parsedSone.getTime(), is(1407197508000L));
535                 assertThat(parsedSone.isLocal(), is(true));
536         }
537
538         @Test
539         public void parsingASoneSucceedsWithoutProtocolVersion() throws SoneException {
540                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-protocol-version.xml");
541                 assertThat(soneParser.parseSone(sone, inputStream), not(
542                                 nullValue()));
543         }
544
545         @Test
546         public void parsingASoneFailsWithMissingClientName() throws SoneException {
547                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-client-name.xml");
548                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
549         }
550
551         @Test
552         public void parsingASoneFailsWithMissingClientVersion() throws SoneException {
553                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-client-version.xml");
554                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
555         }
556
557         @Test
558         public void parsingASoneSucceedsWithClientInfo() throws SoneException {
559                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-client-info.xml");
560                 assertThat(soneParser.parseSone(sone, inputStream).getClient(), is(new Client("some-client", "some-version")));
561         }
562
563         @Test
564         public void parsingASoneSucceedsWithProfile() throws SoneException,
565         MalformedURLException {
566                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-profile.xml");
567                 final Profile profile = soneParser.parseSone(sone, inputStream).getProfile();
568                 assertThat(profile.getFirstName(), is("first"));
569                 assertThat(profile.getMiddleName(), is("middle"));
570                 assertThat(profile.getLastName(), is("last"));
571                 assertThat(profile.getBirthDay(), is(18));
572                 assertThat(profile.getBirthMonth(), is(12));
573                 assertThat(profile.getBirthYear(), is(1976));
574         }
575
576         @Test
577         public void parsingASoneSucceedsWithoutProfileFields() throws SoneException, MalformedURLException {
578                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-fields.xml");
579                 assertThat(soneParser.parseSone(sone, inputStream), notNullValue());
580         }
581
582         @Test
583         public void parsingASoneFailsWithoutPostId() throws SoneException, MalformedURLException {
584                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-id.xml");
585                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
586         }
587
588         @Test
589         public void parsingASoneFailsWithoutPostTime() throws SoneException, MalformedURLException {
590                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-time.xml");
591                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
592         }
593
594         @Test
595         public void parsingASoneFailsWithoutPostText() throws SoneException, MalformedURLException {
596                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-text.xml");
597                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
598         }
599
600         @Test
601         public void parsingASoneFailsWithInvalidPostTime() throws SoneException, MalformedURLException {
602                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-post-time.xml");
603                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
604         }
605
606         @Test
607         public void parsingASoneSucceedsWithValidPostTime() throws SoneException, MalformedURLException {
608                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-valid-post-time.xml");
609                 final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
610                 assertThat(posts, is(createdPosts));
611                 assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
612                 assertThat(posts.get(0).getId(), is("post-id"));
613                 assertThat(posts.get(0).getTime(), is(1407197508000L));
614                 assertThat(posts.get(0).getRecipientId(), is(Optional.<String>absent()));
615                 assertThat(posts.get(0).getText(), is("text"));
616         }
617
618         @Test
619         public void parsingASoneSucceedsWithRecipient() throws SoneException, MalformedURLException {
620                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-recipient.xml");
621                 final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
622                 assertThat(posts, is(createdPosts));
623                 assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
624                 assertThat(posts.get(0).getId(), is("post-id"));
625                 assertThat(posts.get(0).getTime(), is(1407197508000L));
626                 assertThat(posts.get(0).getRecipientId(), is(of(
627                                 "1234567890123456789012345678901234567890123")));
628                 assertThat(posts.get(0).getText(), is("text"));
629         }
630
631         @Test
632         public void parsingASoneSucceedsWithInvalidRecipient() throws SoneException, MalformedURLException {
633                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-recipient.xml");
634                 final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
635                 assertThat(posts, is(createdPosts));
636                 assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
637                 assertThat(posts.get(0).getId(), is("post-id"));
638                 assertThat(posts.get(0).getTime(), is(1407197508000L));
639                 assertThat(posts.get(0).getRecipientId(), is(Optional.<String>absent()));
640                 assertThat(posts.get(0).getText(), is("text"));
641         }
642
643         @Test
644         public void parsingASoneFailsWithoutPostReplyId() throws SoneException, MalformedURLException {
645                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-id.xml");
646                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
647         }
648
649         @Test
650         public void parsingASoneFailsWithoutPostReplyPostId() throws SoneException, MalformedURLException {
651                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-post-id.xml");
652                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
653         }
654
655         @Test
656         public void parsingASoneFailsWithoutPostReplyTime() throws SoneException, MalformedURLException {
657                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-time.xml");
658                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
659         }
660
661         @Test
662         public void parsingASoneFailsWithoutPostReplyText() throws SoneException, MalformedURLException {
663                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-text.xml");
664                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
665         }
666
667         @Test
668         public void parsingASoneFailsWithInvalidPostReplyTime() throws SoneException, MalformedURLException {
669                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-post-reply-time.xml");
670                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
671         }
672
673         @Test
674         public void parsingASoneSucceedsWithValidPostReplyTime() throws SoneException, MalformedURLException {
675                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-valid-post-reply-time.xml");
676                 final Set<PostReply> postReplies = soneParser.parseSone(sone, inputStream).getReplies();
677                 assertThat(postReplies, is(createdPostReplies));
678                 PostReply postReply = createdPostReplies.iterator().next();
679                 assertThat(postReply.getId(), is("reply-id"));
680                 assertThat(postReply.getPostId(), is("post-id"));
681                 assertThat(postReply.getPost().get().getId(), is("post-id"));
682                 assertThat(postReply.getSone().getId(), is("identity"));
683                 assertThat(postReply.getTime(), is(1407197508000L));
684                 assertThat(postReply.getText(), is("reply-text"));
685         }
686
687         @Test
688         public void parsingASoneSucceedsWithoutLikedPostIds() throws SoneException, MalformedURLException {
689                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-liked-post-ids.xml");
690                 assertThat(soneParser.parseSone(sone, inputStream), not(
691                                 nullValue()));
692         }
693
694         @Test
695         public void parsingASoneSucceedsWithLikedPostIds() throws SoneException, MalformedURLException {
696                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-liked-post-ids.xml");
697                 assertThat(soneParser.parseSone(sone, inputStream).getLikedPostIds(), is(
698                                 (Set<String>) ImmutableSet.of("liked-post-id")));
699         }
700
701         @Test
702         public void parsingASoneSucceedsWithoutLikedPostReplyIds() throws SoneException, MalformedURLException {
703                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-liked-post-reply-ids.xml");
704                 assertThat(soneParser.parseSone(sone, inputStream), not(
705                                 nullValue()));
706         }
707
708         @Test
709         public void parsingASoneSucceedsWithLikedPostReplyIds() throws SoneException, MalformedURLException {
710                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-liked-post-reply-ids.xml");
711                 assertThat(soneParser.parseSone(sone, inputStream).getLikedReplyIds(), is(
712                                 (Set<String>) ImmutableSet.of("liked-post-reply-id")));
713         }
714
715         @Test
716         public void parsingASoneSucceedsWithoutAlbums() throws SoneException, MalformedURLException {
717                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-albums.xml");
718                 assertThat(soneParser.parseSone(sone, inputStream), not(
719                                 nullValue()));
720         }
721
722         @Test
723         public void parsingASoneFailsWithoutAlbumId() throws SoneException, MalformedURLException {
724                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-album-id.xml");
725                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
726         }
727
728         @Test
729         public void parsingASoneFailsWithoutAlbumTitle() throws SoneException, MalformedURLException {
730                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-album-title.xml");
731                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
732         }
733
734         @Test
735         public void parsingASoneSucceedsWithNestedAlbums() throws SoneException, MalformedURLException {
736                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-multiple-albums.xml");
737                 final Sone parsedSone = soneParser.parseSone(sone, inputStream);
738                 assertThat(parsedSone, not(nullValue()));
739                 assertThat(parsedSone.getRootAlbum().getAlbums(), hasSize(1));
740                 Album album = parsedSone.getRootAlbum().getAlbums().get(0);
741                 assertThat(album.getId(), is("album-id-1"));
742                 assertThat(album.getTitle(), is("album-title"));
743                 assertThat(album.getDescription(), is("album-description"));
744                 assertThat(album.getAlbums(), hasSize(1));
745                 Album nestedAlbum = album.getAlbums().get(0);
746                 assertThat(nestedAlbum.getId(), is("album-id-2"));
747                 assertThat(nestedAlbum.getTitle(), is("album-title-2"));
748                 assertThat(nestedAlbum.getDescription(), is("album-description-2"));
749                 assertThat(nestedAlbum.getAlbums(), hasSize(0));
750         }
751
752         @Test
753         public void parsingASoneFailsWithInvalidParentAlbumId() throws SoneException, MalformedURLException {
754                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-parent-album-id.xml");
755                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
756         }
757
758         @Test
759         public void parsingASoneSucceedsWithoutImages() throws SoneException, MalformedURLException {
760                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-images.xml");
761                 assertThat(soneParser.parseSone(sone, inputStream), not(
762                                 nullValue()));
763         }
764
765         @Test
766         public void parsingASoneFailsWithoutImageId() throws SoneException, MalformedURLException {
767                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-id.xml");
768                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
769         }
770
771         @Test
772         public void parsingASoneFailsWithoutImageTime() throws SoneException, MalformedURLException {
773                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-time.xml");
774                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
775         }
776
777         @Test
778         public void parsingASoneFailsWithoutImageKey() throws SoneException, MalformedURLException {
779                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-key.xml");
780                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
781         }
782
783         @Test
784         public void parsingASoneFailsWithoutImageTitle() throws SoneException, MalformedURLException {
785                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-title.xml");
786                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
787         }
788
789         @Test
790         public void parsingASoneFailsWithoutImageWidth() throws SoneException, MalformedURLException {
791                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-width.xml");
792                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
793         }
794
795         @Test
796         public void parsingASoneFailsWithoutImageHeight() throws SoneException, MalformedURLException {
797                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-height.xml");
798                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
799         }
800
801         @Test
802         public void parsingASoneFailsWithInvalidImageWidth() throws SoneException, MalformedURLException {
803                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-image-width.xml");
804                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
805         }
806
807         @Test
808         public void parsingASoneFailsWithInvalidImageHeight() throws SoneException, MalformedURLException {
809                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-image-height.xml");
810                 assertThat(soneParser.parseSone(sone, inputStream), nullValue());
811         }
812
813         @Test
814         public void parsingASoneSucceedsWithImage() throws SoneException, MalformedURLException {
815                 InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-image.xml");
816                 final Sone sone = soneParser.parseSone(this.sone, inputStream);
817                 assertThat(sone, not(nullValue()));
818                 assertThat(sone.getRootAlbum().getAlbums(), hasSize(1));
819                 assertThat(sone.getRootAlbum().getAlbums().get(0).getImages(), hasSize(1));
820                 Image image = sone.getRootAlbum().getAlbums().get(0).getImages().get(0);
821                 assertThat(image.getId(), is("image-id"));
822                 assertThat(image.getCreationTime(), is(1407197508000L));
823                 assertThat(image.getKey(), is("KSK@GPLv3.txt"));
824                 assertThat(image.getTitle(), is("image-title"));
825                 assertThat(image.getDescription(), is("image-description"));
826                 assertThat(image.getWidth(), is(1920));
827                 assertThat(image.getHeight(), is(1080));
828                 assertThat(sone.getProfile().getAvatar(), is("image-id"));
829         }
830
831
832 }