From f90d92147c4cff4abe4ae904c6e89d7382b5921e Mon Sep 17 00:00:00 2001 From: =?utf8?q?David=20=E2=80=98Bombe=E2=80=99=20Roden?= Date: Tue, 9 Sep 2014 20:24:37 +0200 Subject: [PATCH] Move image parsing to new configuration parser. --- .../sone/core/ConfigurationSoneParser.java | 63 +++++- .../java/net/pterodactylus/sone/core/Core.java | 37 ++-- src/test/java/net/pterodactylus/sone/Matchers.java | 63 ++++++ .../sone/core/ConfigurationSoneParserTest.java | 219 +++++++++++++++++++++ 4 files changed, 355 insertions(+), 27 deletions(-) diff --git a/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java b/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java index 7b7be9f..3d384c1 100644 --- a/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java +++ b/src/main/java/net/pterodactylus/sone/core/ConfigurationSoneParser.java @@ -1,5 +1,7 @@ package net.pterodactylus.sone.core; +import static java.util.Collections.unmodifiableMap; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -10,11 +12,13 @@ import java.util.Set; import javax.annotation.Nullable; import net.pterodactylus.sone.data.Album; +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.AlbumBuilderFactory; +import net.pterodactylus.sone.database.ImageBuilderFactory; import net.pterodactylus.sone.database.PostBuilder; import net.pterodactylus.sone.database.PostBuilderFactory; import net.pterodactylus.sone.database.PostReplyBuilder; @@ -31,6 +35,8 @@ public class ConfigurationSoneParser { private final Configuration configuration; private final Sone sone; private final String sonePrefix; + private final Map albums = new HashMap(); + private final List topLevelAlbums = new ArrayList(); public ConfigurationSoneParser(Configuration configuration, Sone sone) { this.configuration = configuration; @@ -183,8 +189,6 @@ public class ConfigurationSoneParser { public List parseTopLevelAlbums( AlbumBuilderFactory albumBuilderFactory) { - Map albums = new HashMap(); - List topLevelAlbums = new ArrayList(); int albumCounter = 0; while (true) { String albumPrefix = "/Albums/" + albumCounter++; @@ -224,6 +228,59 @@ public class ConfigurationSoneParser { return topLevelAlbums; } + public Map getAlbums() { + return unmodifiableMap(albums); + } + + public void parseImages(ImageBuilderFactory imageBuilderFactory) { + int imageCounter = 0; + while (true) { + String imagePrefix = "/Images/" + imageCounter++; + String imageId = getString(imagePrefix + "/ID", null); + if (imageId == null) { + break; + } + String albumId = getString(imagePrefix + "/Album", null); + String key = getString(imagePrefix + "/Key", null); + String title = getString(imagePrefix + "/Title", null); + String description = + getString(imagePrefix + "/Description", null); + Long creationTime = getLong(imagePrefix + "/CreationTime", null); + Integer width = getInt(imagePrefix + "/Width", null); + Integer height = getInt(imagePrefix + "/Height", null); + if (albumAttributesAreInvalid(albumId, key, title, description, + creationTime, + width, height)) { + throw new InvalidImageFound(); + } + Album album = albums.get(albumId); + if (album == null) { + throw new InvalidParentAlbumFound(albumId); + } + Image image = imageBuilderFactory.newImageBuilder() + .withId(imageId) + .build() + .modify() + .setSone(sone) + .setCreationTime(creationTime) + .setKey(key) + .setTitle(title) + .setDescription(description) + .setWidth(width) + .setHeight(height) + .update(); + album.addImage(image); + } + } + + private boolean albumAttributesAreInvalid(String albumId, String key, + String title, String description, Long creationTime, + Integer width, Integer height) { + return (albumId == null) || (key == null) || (title == null) || ( + description == null) || (creationTime == null) || (width + == null) || (height == null); + } + public static class InvalidPostFound extends RuntimeException { } public static class InvalidPostReplyFound extends RuntimeException { } @@ -244,4 +301,6 @@ public class ConfigurationSoneParser { } + public static class InvalidImageFound extends RuntimeException { } + } diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index e08acd1..91bd0cc 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -21,6 +21,7 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import static com.google.common.base.Predicates.not; import static java.lang.String.format; +import static java.util.logging.Level.WARNING; import static net.pterodactylus.sone.data.Sone.LOCAL_SONE_FILTER; import java.net.MalformedURLException; @@ -40,6 +41,7 @@ import java.util.logging.Level; import java.util.logging.Logger; 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; @@ -1141,31 +1143,16 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } /* load images. */ - int imageCounter = 0; - while (true) { - String imagePrefix = sonePrefix + "/Images/" + imageCounter++; - String imageId = configuration.getStringValue(imagePrefix + "/ID").getValue(null); - if (imageId == null) { - break; - } - String albumId = configuration.getStringValue(imagePrefix + "/Album").getValue(null); - String key = configuration.getStringValue(imagePrefix + "/Key").getValue(null); - String title = configuration.getStringValue(imagePrefix + "/Title").getValue(null); - String description = configuration.getStringValue(imagePrefix + "/Description").getValue(null); - Long creationTime = configuration.getLongValue(imagePrefix + "/CreationTime").getValue(null); - Integer width = configuration.getIntValue(imagePrefix + "/Width").getValue(null); - Integer height = configuration.getIntValue(imagePrefix + "/Height").getValue(null); - if ((albumId == null) || (key == null) || (title == null) || (description == null) || (creationTime == null) || (width == null) || (height == null)) { - logger.log(Level.WARNING, "Invalid image found, aborting load!"); - return; - } - Album album = getAlbum(albumId); - if (album == null) { - logger.log(Level.WARNING, "Invalid album image encountered, aborting load!"); - return; - } - Image image = getImage(imageId).modify().setSone(sone).setCreationTime(creationTime).setKey(key).setTitle(title).setDescription(description).setWidth(width).setHeight(height).update(); - album.addImage(image); + try { + configurationSoneParser.parseImages(database); + } catch (InvalidImageFound iif) { + logger.log(WARNING, "Invalid image found, aborting load!"); + return; + } catch (InvalidParentAlbumFound ipaf) { + logger.log(Level.WARNING, + format("Invalid album image (%s) encountered, aborting load!", + ipaf.getAlbumParentId())); + return; } /* load avatar. */ diff --git a/src/test/java/net/pterodactylus/sone/Matchers.java b/src/test/java/net/pterodactylus/sone/Matchers.java index c73866e..c1052d5 100644 --- a/src/test/java/net/pterodactylus/sone/Matchers.java +++ b/src/test/java/net/pterodactylus/sone/Matchers.java @@ -23,6 +23,7 @@ import java.io.IOException; import java.io.InputStream; import net.pterodactylus.sone.data.Album; +import net.pterodactylus.sone.data.Image; import net.pterodactylus.sone.data.Post; import net.pterodactylus.sone.data.PostReply; @@ -182,6 +183,68 @@ public class Matchers { }; } + public static Matcher isImage(final String id, + final long creationTime, + final String key, final String title, + final String imageDescription, + final int width, final int height) { + return new TypeSafeDiagnosingMatcher() { + @Override + protected boolean matchesSafely(Image image, + Description mismatchDescription) { + if (!image.getId().equals(id)) { + mismatchDescription.appendText("ID is ") + .appendValue(image.getId()); + return false; + } + if (image.getCreationTime() != creationTime) { + mismatchDescription.appendText("created at @") + .appendValue(image.getCreationTime()); + return false; + } + if (!image.getKey().equals(key)) { + mismatchDescription.appendText("key is ") + .appendValue(image.getKey()); + return false; + } + if (!image.getTitle().equals(title)) { + mismatchDescription.appendText("title is ") + .appendValue(image.getTitle()); + return false; + } + if (!image.getDescription().equals(imageDescription)) { + mismatchDescription.appendText("description is ") + .appendValue(image.getDescription()); + return false; + } + if (image.getWidth() != width) { + mismatchDescription.appendText("width is ") + .appendValue(image.getWidth()); + return false; + } + if (image.getHeight() != height) { + mismatchDescription.appendText("height is ") + .appendValue(image.getHeight()); + return false; + } + return true; + } + + @Override + public void describeTo(Description description) { + description.appendText("image with ID ").appendValue(id); + description.appendText(", created at @") + .appendValue(creationTime); + description.appendText(", has key ").appendValue(key); + description.appendText(", has title ").appendValue(title); + description.appendText(", has description ") + .appendValue(imageDescription); + description.appendText(", has width ").appendValue(width); + description.appendText(", has height ").appendValue(height); + } + }; + } + private static class PostMatcher extends TypeSafeDiagnosingMatcher { private final String postId; diff --git a/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java b/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java index b5e57f7..03b0672 100644 --- a/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java +++ b/src/test/java/net/pterodactylus/sone/core/ConfigurationSoneParserTest.java @@ -5,6 +5,7 @@ import static com.google.common.base.Optional.of; import static java.lang.System.currentTimeMillis; import static java.util.UUID.randomUUID; 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; @@ -25,10 +26,12 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; 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; @@ -42,6 +45,8 @@ 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; @@ -399,6 +404,129 @@ public class ConfigurationSoneParserTest { createAlbumBuilderFactory()); } + @Test + public void imagesAreParsedCorrectly() { + setupTopLevelAlbums(); + configurationSoneParser.parseTopLevelAlbums( + createAlbumBuilderFactory()); + setupImages(); + configurationSoneParser.parseImages(createImageBuilderFactory()); + Map 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() { + @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()); + } + private static class TestValue implements Value { private final AtomicReference value = new AtomicReference(); @@ -657,4 +785,95 @@ public class ConfigurationSoneParserTest { } + private static class TestImageBuilder implements ImageBuilder { + + private final Image image; + + private TestImageBuilder() { + image = mock(Image.class); + Image.Modifier imageModifier = 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.modify()).thenReturn(imageModifier); + } + + @Override + public ImageBuilder randomId() { + when(image.getId()).thenReturn(randomUUID().toString()); + return this; + } + + @Override + public ImageBuilder withId(String id) { + when(image.getId()).thenReturn(id); + return this; + } + + @Override + public Image build() throws IllegalStateException { + return image; + } + + } + } -- 2.7.4