🎨 Replace SoneParserTest with Kotlin version
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Jul 2019 22:08:14 +0000 (00:08 +0200)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Fri, 26 Jul 2019 22:20:39 +0000 (00:20 +0200)
src/main/java/net/pterodactylus/sone/core/SoneParser.java
src/test/java/net/pterodactylus/sone/core/SoneParserTest.java [deleted file]
src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt [new file with mode: 0644]
src/test/resources/net/pterodactylus/sone/core/sone-parser-with-invalid-recipient.xml
src/test/resources/net/pterodactylus/sone/core/sone-parser-with-recipient.xml
src/test/resources/net/pterodactylus/sone/core/sone-parser-with-valid-post-reply-time.xml
src/test/resources/net/pterodactylus/sone/core/sone-parser-with-valid-post-time.xml

index 1f30565..01c056e 100644 (file)
@@ -257,6 +257,7 @@ public class SoneParser {
                SimpleXML albumsXml = soneXml.getNode("albums");
                Map<String, Image> allImages = new HashMap<>();
                List<Album> topLevelAlbums = new ArrayList<>();
+               Map<String, Album> allAlbums = new HashMap<>();
                if (albumsXml != null) {
                        for (SimpleXML albumXml : albumsXml.getNodes("album")) {
                                String id = albumXml.getValue("id", null);
@@ -269,7 +270,7 @@ public class SoneParser {
                                }
                                Album parent = null;
                                if (parentId != null) {
-                                       parent = database.getAlbum(parentId);
+                                       parent = allAlbums.get(parentId);
                                        if (parent == null) {
                                                logger.log(Level.WARNING, String.format("Downloaded Sone %s has album with invalid parent!", sone));
                                                return null;
@@ -288,6 +289,7 @@ public class SoneParser {
                                } else {
                                        topLevelAlbums.add(album);
                                }
+                               allAlbums.put(album.getId(), album);
                                SimpleXML imagesXml = albumXml.getNode("images");
                                if (imagesXml != null) {
                                        for (SimpleXML imageXml : imagesXml.getNodes("image")) {
diff --git a/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/SoneParserTest.java
deleted file mode 100644 (file)
index 400b9ae..0000000
+++ /dev/null
@@ -1,820 +0,0 @@
-package net.pterodactylus.sone.core;
-
-import static com.google.common.base.Optional.of;
-import static freenet.keys.InsertableClientSSK.createRandom;
-import static java.lang.System.currentTimeMillis;
-import static java.util.UUID.randomUUID;
-import static java.util.concurrent.TimeUnit.DAYS;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-import static org.hamcrest.Matchers.not;
-import static org.hamcrest.Matchers.notNullValue;
-import static org.hamcrest.Matchers.nullValue;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyLong;
-import static org.mockito.ArgumentMatchers.anyString;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import java.io.InputStream;
-import java.net.MalformedURLException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-import net.pterodactylus.sone.data.Album;
-import net.pterodactylus.sone.data.Album.Modifier;
-import net.pterodactylus.sone.data.Client;
-import net.pterodactylus.sone.data.Image;
-import net.pterodactylus.sone.data.Post;
-import net.pterodactylus.sone.data.PostReply;
-import net.pterodactylus.sone.data.Profile;
-import net.pterodactylus.sone.data.Sone;
-import net.pterodactylus.sone.database.AlbumBuilder;
-import net.pterodactylus.sone.database.Database;
-import net.pterodactylus.sone.database.ImageBuilder;
-import net.pterodactylus.sone.database.PostBuilder;
-import net.pterodactylus.sone.database.PostReplyBuilder;
-import net.pterodactylus.sone.database.SoneBuilder;
-import net.pterodactylus.sone.database.memory.MemorySoneBuilder;
-import net.pterodactylus.sone.freenet.wot.Identity;
-import net.pterodactylus.sone.freenet.wot.OwnIdentity;
-
-import freenet.crypt.DummyRandomSource;
-import freenet.keys.FreenetURI;
-import freenet.keys.InsertableClientSSK;
-
-import com.google.common.base.Optional;
-import com.google.common.collect.ArrayListMultimap;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ListMultimap;
-import org.junit.Before;
-import org.junit.Test;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-/**
- * Unit test for {@link SoneParser}.
- */
-public class SoneParserTest {
-
-       private final Database database = mock(Database.class);
-       private final SoneParser soneParser = new SoneParser(database);
-       private final Sone sone = mock(Sone.class);
-       private FreenetURI requestUri = mock(FreenetURI.class);
-       private final PostBuilder postBuilder = mock(PostBuilder.class);
-       private final List<Post> createdPosts = new ArrayList<>();
-       private Post post = mock(Post.class);
-       private final PostReplyBuilder postReplyBuilder = mock(PostReplyBuilder.class);
-       private final Set<PostReply> createdPostReplies = new HashSet<>();
-       private PostReply postReply = mock(PostReply.class);
-       private final AlbumBuilder albumBuilder = mock(AlbumBuilder.class);
-       private final ListMultimap<Album, Album>
-                       nestedAlbums = ArrayListMultimap.create();
-       private final ListMultimap<Album, Image> albumImages = ArrayListMultimap.create();
-       private Album album = mock(Album.class);
-       private final Map<String, Album> albums = new HashMap<>();
-       private final ImageBuilder imageBuilder = mock(ImageBuilder.class);
-       private Image image = mock(Image.class);
-       private final Map<String, Image> images = new HashMap<>();
-
-       @Before
-       public void setupSone() {
-               setupSone(this.sone, Identity.class);
-       }
-
-       private void setupSone(Sone sone, Class<? extends Identity> identityClass) {
-               Identity identity = mock(identityClass);
-               InsertableClientSSK clientSSK =
-                               createRandom(new DummyRandomSource(), "WoT");
-               when(identity.getRequestUri()).thenReturn(clientSSK.getURI().toString());
-               when(identity.getId()).thenReturn("identity");
-               when(sone.getId()).thenReturn("identity");
-               when(sone.getIdentity()).thenReturn(identity);
-               requestUri = clientSSK.getURI().setKeyType("USK").setDocName("Sone");
-               when(sone.getRequestUri()).thenAnswer(new Answer<FreenetURI>() {
-                       @Override
-                       public FreenetURI answer(InvocationOnMock invocation)
-                       throws Throwable {
-                               return requestUri;
-                       }
-               });
-               when(sone.getTime())
-                               .thenReturn(currentTimeMillis() - DAYS.toMillis(1));
-       }
-
-       @Before
-       public void setupSoneBuilder() {
-               when(database.newSoneBuilder()).thenAnswer(new Answer<SoneBuilder>() {
-                       @Override
-                       public SoneBuilder answer(InvocationOnMock invocation) {
-                               return new MemorySoneBuilder(null);
-                       }
-               });
-       }
-
-       @Before
-       public void setupPost() {
-               when(post.getRecipientId()).thenReturn(Optional.<String>absent());
-       }
-
-       @Before
-       public void setupPostBuilder() {
-               when(postBuilder.withId(anyString())).thenAnswer(new Answer<PostBuilder>() {
-                       @Override
-                       public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(post.getId()).thenReturn((String) invocation.getArguments()[0]);
-                               return postBuilder;
-                       }
-               });
-               when(postBuilder.from(anyString())).thenAnswer(new Answer<PostBuilder>() {
-                       @Override
-                       public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               final Sone sone = mock(Sone.class);
-                               when(sone.getId()).thenReturn((String) invocation.getArguments()[0]);
-                               when(post.getSone()).thenReturn(sone);
-                               return postBuilder;
-                       }
-               });
-               when(postBuilder.withTime(anyLong())).thenAnswer(new Answer<PostBuilder>() {
-                       @Override
-                       public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(post.getTime()).thenReturn((Long) invocation.getArguments()[0]);
-                               return postBuilder;
-                       }
-               });
-               when(postBuilder.withText(anyString())).thenAnswer(new Answer<PostBuilder>() {
-                       @Override
-                       public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(post.getText()).thenReturn((String) invocation.getArguments()[0]);
-                               return postBuilder;
-                       }
-               });
-               when(postBuilder.to(anyString())).thenAnswer(new Answer<PostBuilder>() {
-                       @Override
-                       public PostBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(post.getRecipientId()).thenReturn(of((String) invocation.getArguments()[0]));
-                               return postBuilder;
-                       }
-               });
-               when(postBuilder.build()).thenAnswer(new Answer<Post>() {
-                       @Override
-                       public Post answer(InvocationOnMock invocation) throws Throwable {
-                               Post post = SoneParserTest.this.post;
-                               SoneParserTest.this.post = mock(Post.class);
-                               setupPost();
-                               createdPosts.add(post);
-                               return post;
-                       }
-               });
-               when(database.newPostBuilder()).thenReturn(postBuilder);
-       }
-
-       @Before
-       public void setupPostReplyBuilder() {
-               when(postReplyBuilder.withId(anyString())).thenAnswer(new Answer<PostReplyBuilder>() {
-                       @Override
-                       public PostReplyBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(postReply.getId()).thenReturn((String) invocation.getArguments()[0]);
-                               return postReplyBuilder;
-                       }
-               });
-               when(postReplyBuilder.from(anyString())).thenAnswer(
-                               new Answer<PostReplyBuilder>() {
-                                       @Override
-                                       public PostReplyBuilder answer(
-                                                       InvocationOnMock invocation) throws Throwable {
-                                               Sone sone = when(mock(Sone.class).getId()).thenReturn(
-                                                               (String) invocation.getArguments()[0])
-                                                               .getMock();
-                                               when(postReply.getSone()).thenReturn(sone);
-                                               return postReplyBuilder;
-                                       }
-                               });
-               when(postReplyBuilder.to(anyString())).thenAnswer(
-                               new Answer<PostReplyBuilder>() {
-                                       @Override
-                                       public PostReplyBuilder answer(
-                                                       InvocationOnMock invocation) throws Throwable {
-                                               when(postReply.getPostId()).thenReturn(
-                                                               (String) invocation.getArguments()[0]);
-                                               Post post = when(mock(Post.class).getId()).thenReturn(
-                                                               (String) invocation.getArguments()[0])
-                                                               .getMock();
-                                               when(postReply.getPost()).thenReturn(of(post));
-                                               return postReplyBuilder;
-                                       }
-                               });
-               when(postReplyBuilder.withTime(anyLong())).thenAnswer(
-                               new Answer<PostReplyBuilder>() {
-                                       @Override
-                                       public PostReplyBuilder answer(
-                                                       InvocationOnMock invocation) throws Throwable {
-                                               when(postReply.getTime()).thenReturn(
-                                                               (Long) invocation.getArguments()[0]);
-                                               return postReplyBuilder;
-                                       }
-                               });
-               when(postReplyBuilder.withText(anyString())).thenAnswer(new Answer<PostReplyBuilder>() {
-                       @Override
-                       public PostReplyBuilder answer(InvocationOnMock invocation) throws Throwable {
-                               when(postReply.getText()).thenReturn((String) invocation.getArguments()[0]);
-                               return postReplyBuilder;
-                       }
-               });
-               when(postReplyBuilder.build()).thenAnswer(new Answer<PostReply>() {
-                       @Override
-                       public PostReply answer(InvocationOnMock invocation) throws Throwable {
-                               PostReply postReply = SoneParserTest.this.postReply;
-                               createdPostReplies.add(postReply);
-                               SoneParserTest.this.postReply = mock(PostReply.class);
-                               return postReply;
-                       }
-               });
-               when(database.newPostReplyBuilder()).thenReturn(postReplyBuilder);
-       }
-
-       @Before
-       public void setupAlbum() {
-               final Album album = SoneParserTest.this.album;
-               doAnswer(new Answer<Void>() {
-                       @Override
-                       public Void answer(InvocationOnMock invocation) {
-                               nestedAlbums.put(album, (Album) invocation.getArguments()[0]);
-                               return null;
-                       }
-               }).when(album).addAlbum(any(Album.class));
-               doAnswer(new Answer<Void>() {
-                       @Override
-                       public Void answer(InvocationOnMock invocation) {
-                               albumImages.put(album, (Image) invocation.getArguments()[0]);
-                               return null;
-                       }
-               }).when(album).addImage(any(Image.class));
-               when(album.getAlbums()).thenAnswer(new Answer<List<Album>>() {
-                       @Override
-                       public List<Album> answer(InvocationOnMock invocation) {
-                               return nestedAlbums.get(album);
-                       }
-               });
-               when(album.getImages()).thenAnswer(new Answer<List<Image>>() {
-                       @Override
-                       public List<Image> answer(InvocationOnMock invocation) {
-                               return albumImages.get(album);
-                       }
-               });
-               final Modifier albumModifier = new Modifier() {
-                       private String title = album.getTitle();
-                       private String description = album.getDescription();
-
-                       @Override
-                       public Modifier setTitle(String title) {
-                               this.title = title;
-                               return this;
-                       }
-
-                       @Override
-                       public Modifier setDescription(String description) {
-                               this.description = description;
-                               return this;
-                       }
-
-                       @Override
-                       public Album update() throws IllegalStateException {
-                               when(album.getTitle()).thenReturn(title);
-                               when(album.getDescription()).thenReturn(description);
-                               return album;
-                       }
-               };
-               when(album.modify()).thenReturn(albumModifier);
-       }
-
-       @Before
-       public void setupAlbumBuilder() {
-               when(albumBuilder.withId(anyString())).thenAnswer(new Answer<AlbumBuilder>() {
-                       @Override
-                       public AlbumBuilder answer(InvocationOnMock invocation) {
-                               when(album.getId()).thenReturn((String) invocation.getArguments()[0]);
-                               return albumBuilder;
-                       }
-               });
-               when(albumBuilder.randomId()).thenAnswer(new Answer<AlbumBuilder>() {
-                       @Override
-                       public AlbumBuilder answer(InvocationOnMock invocation) {
-                               when(album.getId()).thenReturn(randomUUID().toString());
-                               return albumBuilder;
-                       }
-               });
-               when(albumBuilder.by(any(Sone.class))).thenAnswer(new Answer<AlbumBuilder>() {
-                       @Override
-                       public AlbumBuilder answer(InvocationOnMock invocation) {
-                               when(album.getSone()).thenReturn((Sone) invocation.getArguments()[0]);
-                               return albumBuilder;
-                       }
-               });
-               when(albumBuilder.build()).thenAnswer(new Answer<Album>() {
-                       @Override
-                       public Album answer(InvocationOnMock invocation) {
-                               Album album = SoneParserTest.this.album;
-                               albums.put(album.getId(), album);
-                               SoneParserTest.this.album = mock(Album.class);
-                               setupAlbum();
-                               return album;
-                       }
-               });
-               when(database.newAlbumBuilder()).thenReturn(albumBuilder);
-       }
-
-       @Before
-       public void setupAlbums() {
-               when(database.getAlbum(anyString())).thenAnswer(new Answer<Album>() {
-                       @Override
-                       public Album answer(InvocationOnMock invocation)
-                       throws Throwable {
-                               return albums.get(invocation.getArguments()[0]);
-                       }
-               });
-       }
-
-       @Before
-       public void setupImage() {
-               final Image image = SoneParserTest.this.image;
-               Image.Modifier modifier = new Image.Modifier() {
-                       private Sone sone = image.getSone();
-                       private long creationTime = image.getCreationTime();
-                       private String key = image.getKey();
-                       private String title = image.getTitle();
-                       private String description = image.getDescription();
-                       private int width = image.getWidth();
-                       private int height = image.getHeight();
-
-                       @Override
-                       public Image.Modifier setSone(Sone sone) {
-                               this.sone = sone;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setCreationTime(long creationTime) {
-                               this.creationTime = creationTime;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setKey(String key) {
-                               this.key = key;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setTitle(String title) {
-                               this.title = title;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setDescription(String description) {
-                               this.description = description;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setWidth(int width) {
-                               this.width = width;
-                               return this;
-                       }
-
-                       @Override
-                       public Image.Modifier setHeight(int height) {
-                               this.height = height;
-                               return this;
-                       }
-
-                       @Override
-                       public Image update() throws IllegalStateException {
-                               when(image.getSone()).thenReturn(sone);
-                               when(image.getCreationTime()).thenReturn(creationTime);
-                               when(image.getKey()).thenReturn(key);
-                               when(image.getTitle()).thenReturn(title);
-                               when(image.getDescription()).thenReturn(description);
-                               when(image.getWidth()).thenReturn(width);
-                               when(image.getHeight()).thenReturn(height);
-                               return image;
-                       }
-               };
-               when(image.getSone()).thenReturn(sone);
-               when(image.modify()).thenReturn(modifier);
-       }
-
-       @Before
-       public void setupImageBuilder() {
-               when(imageBuilder.randomId()).thenAnswer(new Answer<ImageBuilder>() {
-                       @Override
-                       public ImageBuilder answer(InvocationOnMock invocation) {
-                               when(image.getId()).thenReturn(randomUUID().toString());
-                               return imageBuilder;
-                       }
-               });
-               when(imageBuilder.withId(anyString())).thenAnswer(new Answer<ImageBuilder>() {
-                       @Override
-                       public ImageBuilder answer(InvocationOnMock invocation) {
-                               when(image.getId()).thenReturn(
-                                               (String) invocation.getArguments()[0]);
-                               return imageBuilder;
-                       }
-               });
-               when(imageBuilder.build()).thenAnswer(new Answer<Image>() {
-                       @Override
-                       public Image answer(InvocationOnMock invocation) {
-                               Image image = SoneParserTest.this.image;
-                               images.put(image.getId(), image);
-                               SoneParserTest.this.image = mock(Image.class);
-                               setupImage();
-                               return image;
-                       }
-               });
-               when(database.newImageBuilder()).thenReturn(imageBuilder);
-       }
-
-       @Before
-       public void setupImages() {
-               when(database.getImage(anyString())).thenAnswer(new Answer<Image>() {
-                       @Override
-                       public Image answer(InvocationOnMock invocation)
-                       throws Throwable {
-                               return images.get(invocation.getArguments()[0]);
-                       }
-               });
-       }
-       @Test
-       public void parsingASoneFailsWhenDocumentIsNotXml() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-not-xml.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenDocumentHasNegativeProtocolVersion() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-negative-protocol-version.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenProtocolVersionIsTooLarge() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-too-large-protocol-version.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenThereIsNoTime() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenTimeIsNotNumeric() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-time-not-numeric.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenProfileIsMissing() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-profile.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenProfileFieldIsMissingAFieldName() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-missing-field-name.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenProfileFieldNameIsEmpty() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-empty-field-name.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWhenProfileFieldNameIsNotUnique() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-profile-duplicate-field-name.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutPayload() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-payload.xml");
-               assertThat(soneParser.parseSone(sone, inputStream).getTime(), is(
-                               1407197508000L));
-       }
-
-       @Test
-       public void parsingALocalSoneSucceedsWithoutPayload() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-no-payload.xml");
-               Sone localSone = mock(Sone.class);
-               setupSone(localSone, OwnIdentity.class);
-               when(localSone.isLocal()).thenReturn(true);
-               Sone parsedSone = soneParser.parseSone(localSone, inputStream);
-               assertThat(parsedSone.getTime(), is(1407197508000L));
-               assertThat(parsedSone.isLocal(), is(true));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutProtocolVersion() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-protocol-version.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), not(
-                               nullValue()));
-       }
-
-       @Test
-       public void parsingASoneFailsWithMissingClientName() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-client-name.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithMissingClientVersion() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-missing-client-version.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithClientInfo() throws SoneException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-client-info.xml");
-               assertThat(soneParser.parseSone(sone, inputStream).getClient(), is(new Client("some-client", "some-version")));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithProfile() throws SoneException,
-       MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-profile.xml");
-               final Profile profile = soneParser.parseSone(sone, inputStream).getProfile();
-               assertThat(profile.getFirstName(), is("first"));
-               assertThat(profile.getMiddleName(), is("middle"));
-               assertThat(profile.getLastName(), is("last"));
-               assertThat(profile.getBirthDay(), is(18));
-               assertThat(profile.getBirthMonth(), is(12));
-               assertThat(profile.getBirthYear(), is(1976));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutProfileFields() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-fields.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), notNullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostText() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-text.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithInvalidPostTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-post-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithValidPostTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-valid-post-time.xml");
-               final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
-               assertThat(posts, is(createdPosts));
-               assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
-               assertThat(posts.get(0).getId(), is("post-id"));
-               assertThat(posts.get(0).getTime(), is(1407197508000L));
-               assertThat(posts.get(0).getRecipientId(), is(Optional.<String>absent()));
-               assertThat(posts.get(0).getText(), is("text"));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithRecipient() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-recipient.xml");
-               final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
-               assertThat(posts, is(createdPosts));
-               assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
-               assertThat(posts.get(0).getId(), is("post-id"));
-               assertThat(posts.get(0).getTime(), is(1407197508000L));
-               assertThat(posts.get(0).getRecipientId(), is(of(
-                               "1234567890123456789012345678901234567890123")));
-               assertThat(posts.get(0).getText(), is("text"));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithInvalidRecipient() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-recipient.xml");
-               final List<Post> posts = soneParser.parseSone(sone, inputStream).getPosts();
-               assertThat(posts, is(createdPosts));
-               assertThat(posts.get(0).getSone().getId(), is(sone.getId()));
-               assertThat(posts.get(0).getId(), is("post-id"));
-               assertThat(posts.get(0).getTime(), is(1407197508000L));
-               assertThat(posts.get(0).getRecipientId(), is(Optional.<String>absent()));
-               assertThat(posts.get(0).getText(), is("text"));
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostReplyId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostReplyPostId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-post-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostReplyTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutPostReplyText() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-post-reply-text.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithInvalidPostReplyTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-post-reply-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithValidPostReplyTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-valid-post-reply-time.xml");
-               final Set<PostReply> postReplies = soneParser.parseSone(sone, inputStream).getReplies();
-               assertThat(postReplies, is(createdPostReplies));
-               PostReply postReply = createdPostReplies.iterator().next();
-               assertThat(postReply.getId(), is("reply-id"));
-               assertThat(postReply.getPostId(), is("post-id"));
-               assertThat(postReply.getPost().get().getId(), is("post-id"));
-               assertThat(postReply.getSone().getId(), is("identity"));
-               assertThat(postReply.getTime(), is(1407197508000L));
-               assertThat(postReply.getText(), is("reply-text"));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutLikedPostIds() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-liked-post-ids.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), not(
-                               nullValue()));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithLikedPostIds() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-liked-post-ids.xml");
-               assertThat(soneParser.parseSone(sone, inputStream).getLikedPostIds(), is(
-                               (Set<String>) ImmutableSet.of("liked-post-id")));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutLikedPostReplyIds() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-liked-post-reply-ids.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), not(
-                               nullValue()));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithLikedPostReplyIds() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-liked-post-reply-ids.xml");
-               assertThat(soneParser.parseSone(sone, inputStream).getLikedReplyIds(), is(
-                               (Set<String>) ImmutableSet.of("liked-post-reply-id")));
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutAlbums() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-albums.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), not(
-                               nullValue()));
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutAlbumId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-album-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutAlbumTitle() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-album-title.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithNestedAlbums() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-multiple-albums.xml");
-               final Sone parsedSone = soneParser.parseSone(sone, inputStream);
-               assertThat(parsedSone, not(nullValue()));
-               assertThat(parsedSone.getRootAlbum().getAlbums(), hasSize(1));
-               Album album = parsedSone.getRootAlbum().getAlbums().get(0);
-               assertThat(album.getId(), is("album-id-1"));
-               assertThat(album.getTitle(), is("album-title"));
-               assertThat(album.getDescription(), is("album-description"));
-               assertThat(album.getAlbums(), hasSize(1));
-               Album nestedAlbum = album.getAlbums().get(0);
-               assertThat(nestedAlbum.getId(), is("album-id-2"));
-               assertThat(nestedAlbum.getTitle(), is("album-title-2"));
-               assertThat(nestedAlbum.getDescription(), is("album-description-2"));
-               assertThat(nestedAlbum.getAlbums(), hasSize(0));
-       }
-
-       @Test
-       public void parsingASoneFailsWithInvalidParentAlbumId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-parent-album-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithoutImages() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-images.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), not(
-                               nullValue()));
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageId() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-id.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageTime() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-time.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageKey() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-key.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageTitle() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-title.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageWidth() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-width.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithoutImageHeight() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-without-image-height.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithInvalidImageWidth() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-image-width.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneFailsWithInvalidImageHeight() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-invalid-image-height.xml");
-               assertThat(soneParser.parseSone(sone, inputStream), nullValue());
-       }
-
-       @Test
-       public void parsingASoneSucceedsWithImage() throws SoneException, MalformedURLException {
-               InputStream inputStream = getClass().getResourceAsStream("sone-parser-with-image.xml");
-               final Sone sone = soneParser.parseSone(this.sone, inputStream);
-               assertThat(sone, not(nullValue()));
-               assertThat(sone.getRootAlbum().getAlbums(), hasSize(1));
-               assertThat(sone.getRootAlbum().getAlbums().get(0).getImages(), hasSize(1));
-               Image image = sone.getRootAlbum().getAlbums().get(0).getImages().get(0);
-               assertThat(image.getId(), is("image-id"));
-               assertThat(image.getCreationTime(), is(1407197508000L));
-               assertThat(image.getKey(), is("KSK@GPLv3.txt"));
-               assertThat(image.getTitle(), is("image-title"));
-               assertThat(image.getDescription(), is("image-description"));
-               assertThat(image.getWidth(), is(1920));
-               assertThat(image.getHeight(), is(1080));
-               assertThat(sone.getProfile().getAvatar(), is("image-id"));
-       }
-
-
-}
diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneParserTest.kt
new file mode 100644 (file)
index 0000000..3a7010a
--- /dev/null
@@ -0,0 +1,398 @@
+package net.pterodactylus.sone.core
+
+import com.google.common.base.Optional.*
+import freenet.crypt.*
+import freenet.keys.InsertableClientSSK.*
+import net.pterodactylus.sone.data.*
+import net.pterodactylus.sone.database.memory.*
+import net.pterodactylus.sone.freenet.wot.*
+import net.pterodactylus.sone.test.*
+import net.pterodactylus.util.config.*
+import org.hamcrest.MatcherAssert.*
+import org.hamcrest.Matchers.*
+import org.mockito.Mockito.*
+import java.lang.System.*
+import java.util.concurrent.TimeUnit.*
+import kotlin.test.*
+
+/**
+ * Unit test for [SoneParser].
+ */
+class SoneParserTest {
+
+       private val database = MemoryDatabase(Configuration(MapConfigurationBackend()))
+       private val soneParser = SoneParser(database)
+       private val sone = mock<Sone>()
+
+       @BeforeTest
+       fun setupSone() {
+               setupSone(this.sone, Identity::class.java)
+               database.storeSone(sone)
+       }
+
+       private fun setupSone(sone: Sone, identityClass: Class<out Identity>) {
+               val identity = mock(identityClass)
+               val clientSSK = createRandom(DummyRandomSource(), "WoT")
+               whenever(identity.requestUri).thenReturn(clientSSK.uri.toString())
+               whenever(identity.id).thenReturn("identity")
+               whenever(sone.id).thenReturn("identity")
+               whenever(sone.identity).thenReturn(identity)
+               whenever(sone.requestUri).thenAnswer { clientSSK.uri.setKeyType("USK").setDocName("Sone") }
+               whenever(sone.time).thenReturn(currentTimeMillis() - DAYS.toMillis(1))
+       }
+
+       @Test
+       fun `parsing a sone fails when document is not xml`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-not-xml.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when document has negative protocol version`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-negative-protocol-version.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when protocol version is too large`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-too-large-protocol-version.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when there is no time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-no-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when time is not numeric`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-time-not-numeric.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when profile is missing`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-no-profile.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when profile field is missing afield name`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-profile-missing-field-name.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when profile field name is empty`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-profile-empty-field-name.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails when profile field name is not unique`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-profile-duplicate-field-name.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds without payload`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-no-payload.xml")
+               assertThat(soneParser.parseSone(sone, inputStream)!!.time, equalTo(1407197508000L))
+       }
+
+       @Test
+       fun `parsing a local sone succeeds without payload`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-no-payload.xml")
+               val localSone = mock<Sone>()
+               setupSone(localSone, OwnIdentity::class.java)
+               whenever(localSone.isLocal).thenReturn(true)
+               val parsedSone = soneParser.parseSone(localSone, inputStream)
+               assertThat(parsedSone!!.time, equalTo(1407197508000L))
+               assertThat(parsedSone.isLocal, equalTo(true))
+       }
+
+       @Test
+       fun `parsing a sone succeeds without protocol version`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-missing-protocol-version.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with missing client name`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-missing-client-name.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with missing client version`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-missing-client-version.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with client info`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-client-info.xml")
+               assertThat(soneParser.parseSone(sone, inputStream)!!.client, equalTo(Client("some-client", "some-version")))
+       }
+
+       @Test
+       fun `parsing a sone succeeds with profile`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-profile.xml")
+               val profile = soneParser.parseSone(sone, inputStream)!!.profile
+               assertThat(profile.firstName, equalTo("first"))
+               assertThat(profile.middleName, equalTo("middle"))
+               assertThat(profile.lastName, equalTo("last"))
+               assertThat(profile.birthDay, equalTo(18))
+               assertThat(profile.birthMonth, equalTo(12))
+               assertThat(profile.birthYear, equalTo(1976))
+       }
+
+       @Test
+       fun `parsing a sone succeeds without profile fields`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-fields.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post text`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-text.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with invalid post time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-post-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with valid post time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-valid-post-time.xml")
+               val posts = soneParser.parseSone(sone, inputStream)!!.posts
+               assertThat(posts, hasSize(1))
+               assertThat(posts[0].sone.id, equalTo(sone.id))
+               assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
+               assertThat(posts[0].time, equalTo(1407197508000L))
+               assertThat(posts[0].recipientId, equalTo(absent()))
+               assertThat(posts[0].text, equalTo("text"))
+       }
+
+       @Test
+       fun `parsing a sone succeeds with recipient`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-recipient.xml")
+               val posts = soneParser.parseSone(sone, inputStream)!!.posts
+               assertThat(posts, hasSize(1))
+               assertThat(posts[0].sone.id, equalTo(sone.id))
+               assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
+               assertThat(posts[0].time, equalTo(1407197508000L))
+               assertThat(posts[0].recipientId, equalTo(of("1234567890123456789012345678901234567890123")))
+               assertThat(posts[0].text, equalTo("text"))
+       }
+
+       @Test
+       fun `parsing a sone succeeds with invalid recipient`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-recipient.xml")
+               val posts = soneParser.parseSone(sone, inputStream)!!.posts
+               assertThat(posts, hasSize(1))
+               assertThat(posts[0].sone.id, equalTo(sone.id))
+               assertThat(posts[0].id, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
+               assertThat(posts[0].time, equalTo(1407197508000L))
+               assertThat(posts[0].recipientId, equalTo(absent()))
+               assertThat(posts[0].text, equalTo("text"))
+       }
+
+       @Test
+       fun `parsing a sone fails without post reply id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post reply post id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-post-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post reply time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without post reply text`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-post-reply-text.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with invalid post reply time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-post-reply-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with valid post reply time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-valid-post-reply-time.xml")
+               val postReplies = soneParser.parseSone(sone, inputStream)!!.replies
+               assertThat(postReplies, hasSize(1))
+               val postReply = postReplies.first()
+               assertThat(postReply.id, equalTo("5ccba7f4-aff0-11e9-b176-a7b9db60ce98"))
+               assertThat(postReply.postId, equalTo("3de12680-afef-11e9-a124-e713cf8912fe"))
+               assertThat(postReply.sone.id, equalTo("identity"))
+               assertThat(postReply.time, equalTo(1407197508000L))
+               assertThat(postReply.text, equalTo("reply-text"))
+       }
+
+       @Test
+       fun `parsing a sone succeeds without liked post ids`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-liked-post-ids.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with liked post ids`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-liked-post-ids.xml")
+               assertThat(soneParser.parseSone(sone, inputStream)!!.likedPostIds, equalTo(setOf("liked-post-id")))
+       }
+
+       @Test
+       fun `parsing a sone succeeds without liked post reply ids`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-liked-post-reply-ids.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with liked post reply ids`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-liked-post-reply-ids.xml")
+               assertThat(soneParser.parseSone(sone, inputStream)!!.likedReplyIds, equalTo(setOf("liked-post-reply-id")))
+       }
+
+       @Test
+       fun `parsing a sone succeeds without albums`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-albums.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without album id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-album-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without album title`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-album-title.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with nested albums`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-multiple-albums.xml")
+               val parsedSone = soneParser.parseSone(sone, inputStream)
+               assertThat(parsedSone, notNullValue())
+               assertThat(parsedSone!!.rootAlbum.albums, hasSize(1))
+               val album = parsedSone.rootAlbum.albums[0]
+               assertThat(album.id, equalTo("album-id-1"))
+               assertThat(album.title, equalTo("album-title"))
+               assertThat(album.description, equalTo("album-description"))
+               assertThat(album.albums, hasSize(1))
+               val nestedAlbum = album.albums[0]
+               assertThat(nestedAlbum.id, equalTo("album-id-2"))
+               assertThat(nestedAlbum.title, equalTo("album-title-2"))
+               assertThat(nestedAlbum.description, equalTo("album-description-2"))
+               assertThat(nestedAlbum.albums, hasSize(0))
+       }
+
+       @Test
+       fun `parsing a sone fails with invalid parent album id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-parent-album-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds without images`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-images.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), notNullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image id`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-id.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image time`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-time.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image key`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-key.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image title`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-title.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image width`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-width.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails without image height`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-without-image-height.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with invalid image width`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-image-width.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone fails with invalid image height`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-invalid-image-height.xml")
+               assertThat(soneParser.parseSone(sone, inputStream), nullValue())
+       }
+
+       @Test
+       fun `parsing a sone succeeds with image`() {
+               val inputStream = javaClass.getResourceAsStream("sone-parser-with-image.xml")
+               val sone = soneParser.parseSone(this.sone, inputStream)
+               assertThat(sone, notNullValue())
+               assertThat(sone!!.rootAlbum.albums, hasSize(1))
+               assertThat(sone.rootAlbum.albums[0].images, hasSize(1))
+               val image = sone.rootAlbum.albums[0].images[0]
+               assertThat(image.id, equalTo("image-id"))
+               assertThat(image.creationTime, equalTo(1407197508000L))
+               assertThat(image.key, equalTo("KSK@GPLv3.txt"))
+               assertThat(image.title, equalTo("image-title"))
+               assertThat(image.description, equalTo("image-description"))
+               assertThat(image.width, equalTo(1920))
+               assertThat(image.height, equalTo(1080))
+               assertThat(sone.profile.avatar, equalTo("image-id"))
+       }
+
+}
index e627651..ec7a190 100644 (file)
@@ -5,7 +5,7 @@
        <profile></profile>
        <posts>
                <post>
-                       <id>post-id</id>
+                       <id>3de12680-afef-11e9-a124-e713cf8912fe</id>
                        <time>1407197508000</time>
                        <text>text</text>
                        <recipient>123456789012345678901234567890123456789012</recipient>
index 14dabe1..a6e07ed 100644 (file)
@@ -5,7 +5,7 @@
        <profile></profile>
        <posts>
                <post>
-                       <id>post-id</id>
+                       <id>3de12680-afef-11e9-a124-e713cf8912fe</id>
                        <time>1407197508000</time>
                        <text>text</text>
                        <recipient>1234567890123456789012345678901234567890123</recipient>
index 4d77cb2..c206ef7 100644 (file)
@@ -5,8 +5,8 @@
        <profile></profile>
        <replies>
                <reply>
-                       <id>reply-id</id>
-                       <post-id>post-id</post-id>
+                       <id>5ccba7f4-aff0-11e9-b176-a7b9db60ce98</id>
+                       <post-id>3de12680-afef-11e9-a124-e713cf8912fe</post-id>
                        <time>1407197508000</time>
                        <text>reply-text</text>
                </reply>
index fdfb493..0bc7046 100644 (file)
@@ -5,7 +5,7 @@
        <profile></profile>
        <posts>
                <post>
-                       <id>post-id</id>
+                       <id>3de12680-afef-11e9-a124-e713cf8912fe</id>
                        <time>1407197508000</time>
                        <text>text</text>
                </post>