package net.pterodactylus.sone.core;
import static com.google.common.base.Optional.of;
import static net.pterodactylus.sone.Matchers.isAlbum;
import static net.pterodactylus.sone.Matchers.isImage;
import static net.pterodactylus.sone.Matchers.isPost;
import static net.pterodactylus.sone.Matchers.isPostReply;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.emptyIterable;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import net.pterodactylus.sone.TestAlbumBuilder;
import net.pterodactylus.sone.TestImageBuilder;
import net.pterodactylus.sone.TestPostBuilder;
import net.pterodactylus.sone.TestPostReplyBuilder;
import net.pterodactylus.sone.TestValue;
import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidAlbumFound;
import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidImageFound;
import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidParentAlbumFound;
import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostFound;
import net.pterodactylus.sone.core.ConfigurationSoneParser.InvalidPostReplyFound;
import net.pterodactylus.sone.data.Album;
import net.pterodactylus.sone.data.Post;
import net.pterodactylus.sone.data.PostReply;
import net.pterodactylus.sone.data.Profile;
import net.pterodactylus.sone.data.Profile.Field;
import net.pterodactylus.sone.data.Sone;
import net.pterodactylus.sone.database.AlbumBuilder;
import net.pterodactylus.sone.database.AlbumBuilderFactory;
import net.pterodactylus.sone.database.ImageBuilder;
import net.pterodactylus.sone.database.ImageBuilderFactory;
import net.pterodactylus.sone.database.PostBuilder;
import net.pterodactylus.sone.database.PostBuilderFactory;
import net.pterodactylus.sone.database.PostReplyBuilder;
import net.pterodactylus.sone.database.PostReplyBuilderFactory;
import net.pterodactylus.util.config.Configuration;
import com.google.common.base.Optional;
import org.hamcrest.Matchers;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* Unit test for {@link ConfigurationSoneParser}.
*
* @author <a href="mailto:bombe@pterodactylus.net">David ‘Bombe’ Roden</a>
*/
public class ConfigurationSoneParserTest {
private final Configuration configuration = mock(Configuration.class);
private final Sone sone = mock(Sone.class);
private final ConfigurationSoneParser configurationSoneParser;
public ConfigurationSoneParserTest() {
when(sone.getId()).thenReturn("1");
configurationSoneParser =
new ConfigurationSoneParser(configuration, sone);
}
@Test
public void emptyProfileIsLoadedCorrectly() {
setupEmptyProfile();
Profile profile = configurationSoneParser.parseProfile();
assertThat(profile, notNullValue());
assertThat(profile.getFirstName(), nullValue());
assertThat(profile.getMiddleName(), nullValue());
assertThat(profile.getLastName(), nullValue());
assertThat(profile.getBirthDay(), nullValue());
assertThat(profile.getBirthMonth(), nullValue());
assertThat(profile.getBirthYear(), nullValue());
assertThat(profile.getFields(), emptyIterable());
}
private void setupEmptyProfile() {
when(configuration.getStringValue(anyString())).thenReturn(
TestValue.<String>from(null));
when(configuration.getIntValue(anyString())).thenReturn(
TestValue.<Integer>from(null));
}
@Test
public void filledProfileWithFieldsIsParsedCorrectly() {
setupFilledProfile();
Profile profile = configurationSoneParser.parseProfile();
assertThat(profile, notNullValue());
assertThat(profile.getFirstName(), is("First"));
assertThat(profile.getMiddleName(), is("M."));
assertThat(profile.getLastName(), is("Last"));
assertThat(profile.getBirthDay(), is(18));
assertThat(profile.getBirthMonth(), is(12));
assertThat(profile.getBirthYear(), is(1976));
final List<Field> fields = profile.getFields();
assertThat(fields, hasSize(2));
assertThat(fields.get(0).getName(), is("Field1"));
assertThat(fields.get(0).getValue(), is("Value1"));
assertThat(fields.get(1).getName(), is("Field2"));
assertThat(fields.get(1).getValue(), is("Value2"));
}
private void setupFilledProfile() {
setupString("Sone/1/Profile/FirstName", "First");
setupString("Sone/1/Profile/MiddleName", "M.");
setupString("Sone/1/Profile/LastName", "Last");
setupInteger("Sone/1/Profile/BirthDay", 18);
setupInteger("Sone/1/Profile/BirthMonth", 12);
setupInteger("Sone/1/Profile/BirthYear", 1976);
setupString("Sone/1/Profile/Fields/0/Name", "Field1");
setupString("Sone/1/Profile/Fields/0/Value", "Value1");
setupString("Sone/1/Profile/Fields/1/Name", "Field2");
setupString("Sone/1/Profile/Fields/1/Value", "Value2");
setupString("Sone/1/Profile/Fields/2/Name", null);
}
private void setupString(String nodeName, String value) {
when(configuration.getStringValue(eq(nodeName))).thenReturn(
TestValue.from(value));
}
private void setupInteger(String nodeName, Integer value) {
when(configuration.getIntValue(eq(nodeName))).thenReturn(
TestValue.from(value));
}
@Test
public void postsAreParsedCorrectly() {
setupCompletePosts();
PostBuilderFactory postBuilderFactory = createPostBuilderFactory();
Collection<Post> posts =
configurationSoneParser.parsePosts(postBuilderFactory);
assertThat(posts,
Matchers.<Post>containsInAnyOrder(
isPost("P0", 1000L, "T0", Optional.<String>absent()),
isPost("P1", 1001L, "T1",
of("1234567890123456789012345678901234567890123"))));
}
private PostBuilderFactory createPostBuilderFactory() {
PostBuilderFactory postBuilderFactory =
mock(PostBuilderFactory.class);
when(postBuilderFactory.newPostBuilder()).thenAnswer(
new Answer<PostBuilder>() {
@Override
public PostBuilder answer(InvocationOnMock invocation)
throws Throwable {
return new TestPostBuilder();
}
});
return postBuilderFactory;
}
private void setupCompletePosts() {
setupPost("0", "P0", 1000L, "T0", null);
setupPost("1", "P1", 1001L, "T1",
"1234567890123456789012345678901234567890123");
setupPost("2", null, 0L, null, null);
}
private void setupPost(String postNumber, String postId, long time,
String text, String recipientId) {
setupString("Sone/1/Posts/" + postNumber + "/ID", postId);
setupLong("Sone/1/Posts/" + postNumber + "/Time", time);
setupString("Sone/1/Posts/" + postNumber + "/Text", text);
setupString("Sone/1/Posts/" + postNumber + "/Recipient", recipientId);
}
private void setupLong(String nodeName, Long value) {
when(configuration.getLongValue(eq(nodeName))).thenReturn(
TestValue.from(value));
}
@Test(expected = InvalidPostFound.class)
public void postWithoutTimeIsRecognized() {
setupPostWithoutTime();
configurationSoneParser.parsePosts(createPostBuilderFactory());
}
private void setupPostWithoutTime() {
setupPost("0", "P0", 0L, "T0", null);
}
@Test(expected = InvalidPostFound.class)
public void postWithoutTextIsRecognized() {
setupPostWithoutText();
configurationSoneParser.parsePosts(createPostBuilderFactory());
}
private void setupPostWithoutText() {
setupPost("0", "P0", 1000L, null, null);
}
@Test
public void postWithInvalidRecipientIdIsRecognized() {
setupPostWithInvalidRecipientId();
Collection<Post> posts = configurationSoneParser.parsePosts(
createPostBuilderFactory());
assertThat(posts, contains(
isPost("P0", 1000L, "T0", Optional.<String>absent())));
}
private void setupPostWithInvalidRecipientId() {
setupPost("0", "P0", 1000L, "T0", "123");
setupPost("1", null, 0L, null, null);
}
@Test
public void postRepliesAreParsedCorrectly() {
setupPostReplies();
PostReplyBuilderFactory postReplyBuilderFactory =
new PostReplyBuilderFactory() {
@Override
public PostReplyBuilder newPostReplyBuilder() {
return new TestPostReplyBuilder();
}
};
Collection<PostReply> postReplies =
configurationSoneParser.parsePostReplies(
postReplyBuilderFactory);
assertThat(postReplies, hasSize(2));
assertThat(postReplies,
containsInAnyOrder(isPostReply("R0", "P0", 1000L, "T0"),
isPostReply("R1", "P1", 1001L, "T1")));
}
private void setupPostReplies() {
setupPostReply("0", "R0", "P0", 1000L, "T0");
setupPostReply("1", "R1", "P1", 1001L, "T1");
setupPostReply("2", null, null, 0L, null);
}
private void setupPostReply(String postReplyNumber, String postReplyId,
String postId, long time, String text) {
setupString("Sone/1/Replies/" + postReplyNumber + "/ID", postReplyId);
setupString("Sone/1/Replies/" + postReplyNumber + "/Post/ID", postId);
setupLong("Sone/1/Replies/" + postReplyNumber + "/Time", time);
setupString("Sone/1/Replies/" + postReplyNumber + "/Text", text);
}
@Test(expected = InvalidPostReplyFound.class)
public void missingPostIdIsRecognized() {
setupPostReplyWithMissingPostId();
configurationSoneParser.parsePostReplies(null);
}
private void setupPostReplyWithMissingPostId() {
setupPostReply("0", "R0", null, 1000L, "T0");
}
@Test(expected = InvalidPostReplyFound.class)
public void missingPostReplyTimeIsRecognized() {
setupPostReplyWithMissingPostReplyTime();
configurationSoneParser.parsePostReplies(null);
}
private void setupPostReplyWithMissingPostReplyTime() {
setupPostReply("0", "R0", "P0", 0L, "T0");
}
@Test(expected = InvalidPostReplyFound.class)
public void missingPostReplyTextIsRecognized() {
setupPostReplyWithMissingPostReplyText();
configurationSoneParser.parsePostReplies(null);
}
private void setupPostReplyWithMissingPostReplyText() {
setupPostReply("0", "R0", "P0", 1000L, null);
}
@Test
public void likedPostIdsParsedCorrectly() {
setupLikedPostIds();
Set<String> likedPostIds =
configurationSoneParser.parseLikedPostIds();
assertThat(likedPostIds, containsInAnyOrder("P1", "P2", "P3"));
}
private void setupLikedPostIds() {
setupString("Sone/1/Likes/Post/0/ID", "P1");
setupString("Sone/1/Likes/Post/1/ID", "P2");
setupString("Sone/1/Likes/Post/2/ID", "P3");
setupString("Sone/1/Likes/Post/3/ID", null);
}
@Test
public void likedPostReplyIdsAreParsedCorrectly() {
setupLikedPostReplyIds();
Set<String> likedPostReplyIds =
configurationSoneParser.parseLikedPostReplyIds();
assertThat(likedPostReplyIds, containsInAnyOrder("R1", "R2", "R3"));
}
private void setupLikedPostReplyIds() {
setupString("Sone/1/Likes/Reply/0/ID", "R1");
setupString("Sone/1/Likes/Reply/1/ID", "R2");
setupString("Sone/1/Likes/Reply/2/ID", "R3");
setupString("Sone/1/Likes/Reply/3/ID", null);
}
@Test
public void friendsAreParsedCorrectly() {
setupFriends();
Set<String> friends = configurationSoneParser.parseFriends();
assertThat(friends, containsInAnyOrder("F1", "F2", "F3"));
}
private void setupFriends() {
setupString("Sone/1/Friends/0/ID", "F1");
setupString("Sone/1/Friends/1/ID", "F2");
setupString("Sone/1/Friends/2/ID", "F3");
setupString("Sone/1/Friends/3/ID", null);
}
@Test
public void topLevelAlbumsAreParsedCorrectly() {
setupTopLevelAlbums();
AlbumBuilderFactory albumBuilderFactory = createAlbumBuilderFactory();
List<Album> topLevelAlbums =
configurationSoneParser.parseTopLevelAlbums(
albumBuilderFactory);
assertThat(topLevelAlbums, hasSize(2));
Album firstAlbum = topLevelAlbums.get(0);
assertThat(firstAlbum, isAlbum("A1", null, "T1", "D1"));
assertThat(firstAlbum.getAlbums(), emptyIterable());
assertThat(firstAlbum.getImages(), emptyIterable());
Album secondAlbum = topLevelAlbums.get(1);
assertThat(secondAlbum, isAlbum("A2", null, "T2", "D2"));
assertThat(secondAlbum.getAlbums(), hasSize(1));
assertThat(secondAlbum.getImages(), emptyIterable());
Album thirdAlbum = secondAlbum.getAlbums().get(0);
assertThat(thirdAlbum, isAlbum("A3", "A2", "T3", "D3"));
assertThat(thirdAlbum.getAlbums(), emptyIterable());
assertThat(thirdAlbum.getImages(), emptyIterable());
}
private void setupTopLevelAlbums() {
setupAlbum(0, "A1", null, "T1", "D1", "I1");
setupAlbum(1, "A2", null, "T2", "D2", null);
setupAlbum(2, "A3", "A2", "T3", "D3", "I3");
setupAlbum(3, null, null, null, null, null);
}
private void setupAlbum(int albumNumber, String albumId,
String parentAlbumId,
String title, String description, String imageId) {
final String albumPrefix = "Sone/1/Albums/" + albumNumber;
setupString(albumPrefix + "/ID", albumId);
setupString(albumPrefix + "/Title", title);
setupString(albumPrefix + "/Description", description);
setupString(albumPrefix + "/Parent", parentAlbumId);
setupString(albumPrefix + "/AlbumImage", imageId);
}
private AlbumBuilderFactory createAlbumBuilderFactory() {
AlbumBuilderFactory albumBuilderFactory =
mock(AlbumBuilderFactory.class);
when(albumBuilderFactory.newAlbumBuilder()).thenAnswer(
new Answer<AlbumBuilder>() {
@Override
public AlbumBuilder answer(InvocationOnMock invocation) {
return new TestAlbumBuilder();
}
});
return albumBuilderFactory;
}
@Test(expected = InvalidAlbumFound.class)
public void albumWithInvalidTitleIsRecognized() {
setupAlbum(0, "A1", null, null, "D1", "I1");
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
}
@Test(expected = InvalidAlbumFound.class)
public void albumWithInvalidDescriptionIsRecognized() {
setupAlbum(0, "A1", null, "T1", null, "I1");
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
}
@Test(expected = InvalidParentAlbumFound.class)
public void albumWithInvalidParentIsRecognized() {
setupAlbum(0, "A1", "A0", "T1", "D1", "I1");
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
}
@Test
public void imagesAreParsedCorrectly() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImages();
configurationSoneParser.parseImages(createImageBuilderFactory());
Map<String, Album> albums = configurationSoneParser.getAlbums();
assertThat(albums.get("A1").getImages(),
contains(isImage("I1", 1000L, "K1", "T1", "D1", 16, 9)));
assertThat(albums.get("A2").getImages(), contains(
isImage("I2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2)));
assertThat(albums.get("A3").getImages(), contains(
isImage("I3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3)));
}
private void setupImages() {
setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, 9);
setupImage(1, "I2", "A2", 2000L, "K2", "T2", "D2", 16 * 2, 9 * 2);
setupImage(2, "I3", "A3", 3000L, "K3", "T3", "D3", 16 * 3, 9 * 3);
setupImage(3, null, null, 0L, null, null, null, 0, 0);
}
private void setupImage(int imageNumber, String id,
String parentAlbumId, Long creationTime, String key, String title,
String description, Integer width, Integer height) {
final String imagePrefix = "Sone/1/Images/" + imageNumber;
setupString(imagePrefix + "/ID", id);
setupString(imagePrefix + "/Album", parentAlbumId);
setupLong(imagePrefix + "/CreationTime", creationTime);
setupString(imagePrefix + "/Key", key);
setupString(imagePrefix + "/Title", title);
setupString(imagePrefix + "/Description", description);
setupInteger(imagePrefix + "/Width", width);
setupInteger(imagePrefix + "/Height", height);
}
private ImageBuilderFactory createImageBuilderFactory() {
ImageBuilderFactory imageBuilderFactory =
mock(ImageBuilderFactory.class);
when(imageBuilderFactory.newImageBuilder()).thenAnswer(
new Answer<ImageBuilder>() {
@Override
public ImageBuilder answer(InvocationOnMock invocation)
throws Throwable {
return new TestImageBuilder();
}
});
return imageBuilderFactory;
}
@Test(expected = InvalidImageFound.class)
public void missingAlbumIdIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", null, 1000L, "K1", "T1", "D1", 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidParentAlbumFound.class)
public void invalidAlbumIdIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A4", 1000L, "K1", "T1", "D1", 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingCreationTimeIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", null, "K1", "T1", "D1", 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingKeyIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", 1000L, null, "T1", "D1", 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingTitleIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", 1000L, "K1", null, "D1", 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingDescriptionIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", 1000L, "K1", "T1", null, 16, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingWidthIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", null, 9);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
@Test(expected = InvalidImageFound.class)
public void missingHeightIsRecognized() {
setupTopLevelAlbums();
configurationSoneParser.parseTopLevelAlbums(
createAlbumBuilderFactory());
setupImage(0, "I1", "A1", 1000L, "K1", "T1", "D1", 16, null);
configurationSoneParser.parseImages(createImageBuilderFactory());
}
}