From: David ‘Bombe’ Roden Date: Fri, 22 Feb 2019 21:28:35 +0000 (+0100) Subject: Merge branch 'next' of calcium:git/Sone into next X-Git-Tag: v79^2~107 X-Git-Url: https://git.pterodactylus.net/?p=Sone.git;a=commitdiff_plain;h=a9fe72ff6a8605b52cda9f55108a344eda749f47;hp=f5fc7fdf598e1a10757069e0701c41a86047d266 Merge branch 'next' of calcium:git/Sone into next --- diff --git a/src/main/java/net/pterodactylus/sone/core/Core.java b/src/main/java/net/pterodactylus/sone/core/Core.java index 4319d8b..8e20176 100644 --- a/src/main/java/net/pterodactylus/sone/core/Core.java +++ b/src/main/java/net/pterodactylus/sone/core/Core.java @@ -48,8 +48,6 @@ 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.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; import net.pterodactylus.sone.core.event.ImageInsertFinishedEvent; import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; import net.pterodactylus.sone.core.event.MarkPostKnownEvent; @@ -851,48 +849,33 @@ public class Core extends AbstractService implements SoneProvider, PostProvider, } } - private List collectEventsForChangesInSone(Sone oldSone, - final Sone newSone) { - final List events = new ArrayList(); - SoneChangeDetector soneChangeDetector = new SoneChangeDetector( - oldSone); - soneChangeDetector.onNewPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - if (post.getSone().equals(newSone)) { - post.setKnown(true); - } else if (post.getTime() < database.getFollowingTime(newSone.getId())) { - post.setKnown(true); - } else if (!post.isKnown()) { - events.add(new NewPostFoundEvent(post)); - } - } - }); - soneChangeDetector.onRemovedPosts(new PostProcessor() { - @Override - public void processPost(Post post) { - events.add(new PostRemovedEvent(post)); - } - }); - soneChangeDetector.onNewPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - if (postReply.getSone().equals(newSone)) { - postReply.setKnown(true); - } else if (postReply.getTime() < database.getFollowingTime(newSone.getId())) { - postReply.setKnown(true); - } else if (!postReply.isKnown()) { - events.add(new NewPostReplyFoundEvent(postReply)); - } + private List collectEventsForChangesInSone(Sone oldSone, Sone newSone) { + List events = new ArrayList<>(); + SoneComparison soneComparison = new SoneComparison(oldSone, newSone); + for (Post newPost : soneComparison.getNewPosts()) { + if (newPost.getSone().equals(newSone)) { + newPost.setKnown(true); + } else if (newPost.getTime() < database.getFollowingTime(newSone.getId())) { + newPost.setKnown(true); + } else if (!newPost.isKnown()) { + events.add(new NewPostFoundEvent(newPost)); } - }); - soneChangeDetector.onRemovedPostReplies(new PostReplyProcessor() { - @Override - public void processPostReply(PostReply postReply) { - events.add(new PostReplyRemovedEvent(postReply)); + } + for (Post post : soneComparison.getRemovedPosts()) { + events.add(new PostRemovedEvent(post)); + } + for (PostReply postReply : soneComparison.getNewPostReplies()) { + if (postReply.getSone().equals(newSone)) { + postReply.setKnown(true); + } else if (postReply.getTime() < database.getFollowingTime(newSone.getId())) { + postReply.setKnown(true); + } else if (!postReply.isKnown()) { + events.add(new NewPostReplyFoundEvent(postReply)); } - }); - soneChangeDetector.detectChanges(newSone); + } + for (PostReply postReply : soneComparison.getRemovedPostReplies()) { + events.add(new PostReplyRemovedEvent(postReply)); + } return events; } diff --git a/src/main/java/net/pterodactylus/sone/core/Preferences.java b/src/main/java/net/pterodactylus/sone/core/Preferences.java index ce56e8b..73d964c 100644 --- a/src/main/java/net/pterodactylus/sone/core/Preferences.java +++ b/src/main/java/net/pterodactylus/sone/core/Preferences.java @@ -137,6 +137,7 @@ public class Preferences { */ public Preferences setPostsPerPage(Integer postsPerPage) { this.postsPerPage.set(postsPerPage); + eventBus.post(new PreferenceChangedEvent("PostsPerPage", getPostsPerPage())); return this; } diff --git a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java b/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java deleted file mode 100644 index 7dd882d..0000000 --- a/src/main/java/net/pterodactylus/sone/core/SoneChangeDetector.java +++ /dev/null @@ -1,112 +0,0 @@ -package net.pterodactylus.sone.core; - -import static com.google.common.base.Optional.absent; -import static com.google.common.base.Optional.fromNullable; -import static com.google.common.collect.FluentIterable.from; - -import java.util.Collection; - -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import com.google.common.base.Optional; -import com.google.common.base.Predicate; -import com.google.common.collect.FluentIterable; - -/** - * Compares the contents of two {@link Sone}s and fires events for new and - * removed elements. - */ -public class SoneChangeDetector { - - private final Sone oldSone; - private Optional newPostProcessor = absent(); - private Optional removedPostProcessor = absent(); - private Optional newPostReplyProcessor = absent(); - private Optional removedPostReplyProcessor = absent(); - - public SoneChangeDetector(Sone oldSone) { - this.oldSone = oldSone; - } - - public void onNewPosts(PostProcessor newPostProcessor) { - this.newPostProcessor = fromNullable(newPostProcessor); - } - - public void onRemovedPosts(PostProcessor removedPostProcessor) { - this.removedPostProcessor = fromNullable(removedPostProcessor); - } - - public void onNewPostReplies(PostReplyProcessor newPostReplyProcessor) { - this.newPostReplyProcessor = fromNullable(newPostReplyProcessor); - } - - public void onRemovedPostReplies( - PostReplyProcessor removedPostReplyProcessor) { - this.removedPostReplyProcessor = fromNullable(removedPostReplyProcessor); - } - - public void detectChanges(Sone newSone) { - processPosts(from(newSone.getPosts()).filter( - notContainedIn(oldSone.getPosts())), newPostProcessor); - processPosts(from(oldSone.getPosts()).filter( - notContainedIn(newSone.getPosts())), removedPostProcessor); - processPostReplies(from(newSone.getReplies()).filter( - notContainedIn(oldSone.getReplies())), newPostReplyProcessor); - processPostReplies(from(oldSone.getReplies()).filter( - notContainedIn(newSone.getReplies())), removedPostReplyProcessor); - } - - private void processPostReplies(FluentIterable postReplies, - Optional postReplyProcessor) { - for (PostReply postReply : postReplies) { - notifyPostReplyProcessor(postReplyProcessor, postReply); - } - } - - private void notifyPostReplyProcessor( - Optional postReplyProcessor, - PostReply postReply) { - if (postReplyProcessor.isPresent()) { - postReplyProcessor.get() - .processPostReply(postReply); - } - } - - private void processPosts(FluentIterable posts, - Optional newPostProcessor) { - for (Post post : posts) { - notifyPostProcessor(newPostProcessor, post); - } - } - - private void notifyPostProcessor(Optional postProcessor, - Post newPost) { - if (postProcessor.isPresent()) { - postProcessor.get().processPost(newPost); - } - } - - private Predicate notContainedIn(final Collection posts) { - return new Predicate() { - @Override - public boolean apply(T element) { - return !posts.contains(element); - } - }; - } - - public interface PostProcessor { - - void processPost(Post post); - - } - - public interface PostReplyProcessor { - - void processPostReply(PostReply postReply); - - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt b/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt deleted file mode 100644 index 609a55f..0000000 --- a/src/main/kotlin/net/pterodactylus/sone/core/SoneChangeCollector.kt +++ /dev/null @@ -1,49 +0,0 @@ -package net.pterodactylus.sone.core - -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone - -/** - * Wrapper around a [SoneChangeDetector] that can turn changed elements into - * different elements which are then being returned. This can be used to turn - * changed elements into events for further processing. - */ -class SoneChangeCollector(private val oldSone: Sone) { - - private val newPostEventCreators = mutableListOf<(Post) -> Any?>() - private val removedPostEventCreators = mutableListOf<(Post) -> Any?>() - private val newPostReplyEventCreators = mutableListOf<(PostReply) -> Any?>() - private val removedPostReplyEventCreators = mutableListOf<(PostReply) -> Any?>() - - fun onNewPost(postProcessor: (Post) -> Unit) = - newPostEventCreators.add { postProcessor(it).let { null } }.let { this } - - fun newPostEvent(postEventCreator: (Post) -> Any?) = - newPostEventCreators.add(postEventCreator).let { this } - - fun onNewPostReply(postReplyProcessor: (PostReply) -> Unit) = - newPostReplyEventCreators.add { postReplyProcessor(it).let { null } }.let { this } - - fun newPostReplyEvent(postReplyEventCreator: (PostReply) -> Any?) = - newPostReplyEventCreators.add(postReplyEventCreator).let { this } - - fun removedPostEvent(postEventCreator: (Post) -> Any?) = - removedPostEventCreators.add(postEventCreator).let { this } - - fun onRemovedPostReply(postReplyEventCreator: (PostReply) -> Any?) = - removedPostReplyEventCreators.add(postReplyEventCreator).let { this } - - fun detectChanges(newSone: Sone): List { - val events = mutableListOf() - SoneChangeDetector(oldSone).apply { - onNewPosts { post -> newPostEventCreators.mapNotNull { it(post) }.forEach { events.add(it) } } - onRemovedPosts { post -> removedPostEventCreators.mapNotNull { it(post) }.forEach { events.add(it) } } - onNewPostReplies { reply -> newPostReplyEventCreators.mapNotNull { it(reply) }.forEach { events.add(it) } } - onRemovedPostReplies { reply -> removedPostReplyEventCreators.mapNotNull { it(reply) }.forEach { events.add(it) } } - detectChanges(newSone) - } - return events - } - -} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt new file mode 100644 index 0000000..9a67f80 --- /dev/null +++ b/src/main/kotlin/net/pterodactylus/sone/core/SoneComparison.kt @@ -0,0 +1,12 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* + +class SoneComparison(private val oldSone: Sone, private val newSone: Sone) { + + val newPosts: Collection get() = newSone.posts - oldSone.posts + val removedPosts: Collection get() = oldSone.posts - newSone.posts + val newPostReplies: Collection get() = newSone.replies - oldSone.replies + val removedPostReplies: Collection get() = oldSone.replies - newSone.replies + +} diff --git a/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt index 580f227..ebaa3c8 100644 --- a/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt +++ b/src/main/kotlin/net/pterodactylus/sone/core/UpdatedSoneProcessor.kt @@ -1,16 +1,13 @@ package net.pterodactylus.sone.core -import com.google.common.eventbus.EventBus -import com.google.inject.ImplementedBy -import net.pterodactylus.sone.core.event.NewPostFoundEvent -import net.pterodactylus.sone.core.event.NewPostReplyFoundEvent -import net.pterodactylus.sone.core.event.PostRemovedEvent -import net.pterodactylus.sone.core.event.PostReplyRemovedEvent -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.data.Sone.SoneStatus -import net.pterodactylus.sone.database.Database -import net.pterodactylus.sone.utils.ifFalse -import net.pterodactylus.util.logging.Logging +import com.google.common.eventbus.* +import com.google.inject.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.data.Sone.* +import net.pterodactylus.sone.database.* +import net.pterodactylus.sone.utils.* +import net.pterodactylus.util.logging.* import javax.inject.Inject /** @@ -35,9 +32,23 @@ abstract class BasicUpdateSoneProcessor(private val database: Database, private logger.fine("Downloaded Sone $sone can not update stored Sone $storedSone.") return } - collectEventsForChanges(storedSone, sone) - .also { database.storeSone(sone) } - .forEach(eventBus::post) + + SoneComparison(storedSone, sone).apply { + newPosts + .onEach { post -> if (post.time <= sone.followingTime) post.isKnown = true } + .mapNotNull { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } } + .forEach(eventBus::post) + removedPosts + .map { PostRemovedEvent(it) } + .forEach(eventBus::post) + newPostReplies + .onEach { postReply -> if (postReply.time <= sone.followingTime) postReply.isKnown = true } + .mapNotNull { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } } + .forEach(eventBus::post) + removedPostReplies + .map { PostReplyRemovedEvent(it) } + .forEach(eventBus::post) + } sone.options = storedSone.options sone.isKnown = storedSone.isKnown sone.status = if (sone.time != 0L) SoneStatus.idle else SoneStatus.unknown @@ -47,16 +58,6 @@ abstract class BasicUpdateSoneProcessor(private val database: Database, private private val Sone.followingTime get() = database.getFollowingTime(id) ?: 0 - private fun collectEventsForChanges(oldSone: Sone, newSone: Sone): List = - SoneChangeCollector(oldSone) - .onNewPost { post -> if (post.time <= newSone.followingTime) post.isKnown = true } - .newPostEvent { post -> post.isKnown.ifFalse { NewPostFoundEvent(post) } } - .removedPostEvent { PostRemovedEvent(it) } - .onNewPostReply { postReply -> if (postReply.time <= newSone.followingTime) postReply.isKnown = true } - .newPostReplyEvent { postReply -> postReply.isKnown.ifFalse { NewPostReplyFoundEvent(postReply) } } - .onRemovedPostReply { PostReplyRemovedEvent(it) } - .detectChanges(newSone) - } class DefaultUpdateSoneProcessor @Inject constructor(database: Database, eventBus: EventBus) : diff --git a/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java b/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java deleted file mode 100644 index fdae222..0000000 --- a/src/test/java/net/pterodactylus/sone/core/PreferencesTest.java +++ /dev/null @@ -1,319 +0,0 @@ -package net.pterodactylus.sone.core; - -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.ALWAYS; -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.NO; -import static net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.WRITING; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.hasItem; -import static org.hamcrest.Matchers.is; -import static org.mockito.ArgumentCaptor.forClass; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.atLeastOnce; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.verify; - -import net.pterodactylus.sone.core.event.InsertionDelayChangedEvent; -import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired; -import net.pterodactylus.sone.fcp.event.FcpInterfaceActivatedEvent; -import net.pterodactylus.sone.fcp.event.FcpInterfaceDeactivatedEvent; -import net.pterodactylus.sone.fcp.event.FullAccessRequiredChanged; - -import com.google.common.eventbus.EventBus; -import org.junit.Test; -import org.mockito.ArgumentCaptor; - -/** - * Unit test for {@link Preferences}. - */ -public class PreferencesTest { - - private final EventBus eventBus = mock(EventBus.class); - private final Preferences preferences = new Preferences(eventBus); - - @Test - public void preferencesRetainInsertionDelay() { - preferences.setInsertionDelay(15); - assertThat(preferences.getInsertionDelay(), is(15)); - } - - @Test - public void preferencesSendsEventOnSettingInsertionDelay() { - preferences.setInsertionDelay(15); - ArgumentCaptor eventsCaptor = forClass(Object.class); - verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()); - assertThat(eventsCaptor.getAllValues(), hasItem(new InsertionDelayChangedEvent(15))); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidInsertionDelayIsRejected() { - preferences.setInsertionDelay(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenInsertionDelayIsSetToNull() { - preferences.setInsertionDelay(null); - assertThat(preferences.getInsertionDelay(), is(60)); - } - - @Test - public void preferencesStartWithInsertionDelayDefaultValue() { - assertThat(preferences.getInsertionDelay(), is(60)); - } - - @Test - public void preferencesRetainPostsPerPage() { - preferences.setPostsPerPage(15); - assertThat(preferences.getPostsPerPage(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPostsPerPageIsRejected() { - preferences.setPostsPerPage(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenPostsPerPageIsSetToNull() { - preferences.setPostsPerPage(null); - assertThat(preferences.getPostsPerPage(), is(10)); - } - - @Test - public void preferencesStartWithPostsPerPageDefaultValue() { - assertThat(preferences.getPostsPerPage(), is(10)); - } - - @Test - public void preferencesRetainImagesPerPage() { - preferences.setImagesPerPage(15); - assertThat(preferences.getImagesPerPage(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidImagesPerPageIsRejected() { - preferences.setImagesPerPage(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenImagesPerPageIsSetToNull() { - preferences.setImagesPerPage(null); - assertThat(preferences.getImagesPerPage(), is(9)); - } - - @Test - public void preferencesStartWithImagesPerPageDefaultValue() { - assertThat(preferences.getImagesPerPage(), is(9)); - } - - @Test - public void preferencesRetainCharactersPerPost() { - preferences.setCharactersPerPost(150); - assertThat(preferences.getCharactersPerPost(), is(150)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidCharactersPerPostIsRejected() { - preferences.setCharactersPerPost(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenCharactersPerPostIsSetToNull() { - preferences.setCharactersPerPost(null); - assertThat(preferences.getCharactersPerPost(), is(400)); - } - - @Test - public void preferencesStartWithCharactersPerPostDefaultValue() { - assertThat(preferences.getCharactersPerPost(), is(400)); - } - - @Test - public void preferencesRetainPostCutOffLength() { - preferences.setPostCutOffLength(150); - assertThat(preferences.getPostCutOffLength(), is(150)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPostCutOffLengthIsRejected() { - preferences.setPostCutOffLength(-15); - } - - @Test(expected = IllegalArgumentException.class) - public void cutOffLengthOfMinusOneIsNotAllowed() { - preferences.setPostCutOffLength(-1); - } - - @Test - public void preferencesReturnDefaultValueWhenPostCutOffLengthIsSetToNull() { - preferences.setPostCutOffLength(null); - assertThat(preferences.getPostCutOffLength(), is(200)); - } - - @Test - public void preferencesStartWithPostCutOffLengthDefaultValue() { - assertThat(preferences.getPostCutOffLength(), is(200)); - } - - @Test - public void preferencesRetainRequireFullAccessOfTrue() { - preferences.setRequireFullAccess(true); - assertThat(preferences.isRequireFullAccess(), is(true)); - } - - @Test - public void preferencesRetainRequireFullAccessOfFalse() { - preferences.setRequireFullAccess(false); - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesReturnDefaultValueWhenRequireFullAccessIsSetToNull() { - preferences.setRequireFullAccess(null); - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesStartWithRequireFullAccessDefaultValue() { - assertThat(preferences.isRequireFullAccess(), is(false)); - } - - @Test - public void preferencesRetainPositiveTrust() { - preferences.setPositiveTrust(15); - assertThat(preferences.getPositiveTrust(), is(15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidPositiveTrustIsRejected() { - preferences.setPositiveTrust(-15); - } - - @Test - public void preferencesReturnDefaultValueWhenPositiveTrustIsSetToNull() { - preferences.setPositiveTrust(null); - assertThat(preferences.getPositiveTrust(), is(75)); - } - - @Test - public void preferencesStartWithPositiveTrustDefaultValue() { - assertThat(preferences.getPositiveTrust(), is(75)); - } - - @Test - public void preferencesRetainNegativeTrust() { - preferences.setNegativeTrust(-15); - assertThat(preferences.getNegativeTrust(), is(-15)); - } - - @Test(expected = IllegalArgumentException.class) - public void invalidNegativeTrustIsRejected() { - preferences.setNegativeTrust(150); - } - - @Test - public void preferencesReturnDefaultValueWhenNegativeTrustIsSetToNull() { - preferences.setNegativeTrust(null); - assertThat(preferences.getNegativeTrust(), is(-25)); - } - - @Test - public void preferencesStartWithNegativeTrustDefaultValue() { - assertThat(preferences.getNegativeTrust(), is(-25)); - } - - @Test - public void preferencesRetainTrustComment() { - preferences.setTrustComment("Trust"); - assertThat(preferences.getTrustComment(), is("Trust")); - } - - @Test - public void preferencesReturnDefaultValueWhenTrustCommentIsSetToNull() { - preferences.setTrustComment(null); - assertThat(preferences.getTrustComment(), - is("Set from Sone Web Interface")); - } - - @Test - public void preferencesStartWithTrustCommentDefaultValue() { - assertThat(preferences.getTrustComment(), - is("Set from Sone Web Interface")); - } - - @Test - public void preferencesRetainFcpInterfaceActiveOfTrue() { - preferences.setFcpInterfaceActive(true); - assertThat(preferences.isFcpInterfaceActive(), is(true)); - verify(eventBus).post(any(FcpInterfaceActivatedEvent.class)); - } - - @Test - public void preferencesRetainFcpInterfaceActiveOfFalse() { - preferences.setFcpInterfaceActive(false); - assertThat(preferences.isFcpInterfaceActive(), is(false)); - verify(eventBus).post(any(FcpInterfaceDeactivatedEvent.class)); - } - - @Test - public void preferencesReturnDefaultValueWhenFcpInterfaceActiveIsSetToNull() { - preferences.setFcpInterfaceActive(null); - assertThat(preferences.isFcpInterfaceActive(), is(false)); - verify(eventBus).post(any(FcpInterfaceDeactivatedEvent.class)); - } - - @Test - public void preferencesStartWithFcpInterfaceActiveDefaultValue() { - assertThat(preferences.isFcpInterfaceActive(), is(false)); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfNo() { - preferences.setFcpFullAccessRequired(NO); - assertThat(preferences.getFcpFullAccessRequired(), is(NO)); - verifyFullAccessRequiredChangedEvent(NO); - } - - private void verifyFullAccessRequiredChangedEvent( - FullAccessRequired fullAccessRequired) { - ArgumentCaptor fullAccessRequiredCaptor = - forClass(FullAccessRequiredChanged.class); - verify(eventBus).post(fullAccessRequiredCaptor.capture()); - assertThat( - fullAccessRequiredCaptor.getValue().getFullAccessRequired(), - is(fullAccessRequired)); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfWriting() { - preferences.setFcpFullAccessRequired(WRITING); - assertThat(preferences.getFcpFullAccessRequired(), is(WRITING)); - verifyFullAccessRequiredChangedEvent(WRITING); - } - - @Test - public void preferencesRetainFcpFullAccessRequiredOfAlways() { - preferences.setFcpFullAccessRequired(ALWAYS); - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - verifyFullAccessRequiredChangedEvent(ALWAYS); - } - - @Test - public void preferencesReturnDefaultValueWhenFcpFullAccessRequiredIsSetToNull() { - preferences.setFcpFullAccessRequired(null); - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - verifyFullAccessRequiredChangedEvent(ALWAYS); - } - - @Test - public void preferencesStartWithFcpFullAccessRequiredDefaultValue() { - assertThat(preferences.getFcpFullAccessRequired(), is(ALWAYS)); - } - - @Test - public void settingInsertionDelayToValidValueSendsChangeEvent() { - preferences.setInsertionDelay(30); - ArgumentCaptor eventsCaptor = forClass(Object.class); - verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()); - assertThat(eventsCaptor.getAllValues(), hasItem(new PreferenceChangedEvent("InsertionDelay", 30))); - } - -} diff --git a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java b/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java deleted file mode 100644 index eaa9637..0000000 --- a/src/test/java/net/pterodactylus/sone/core/SoneChangeDetectorTest.java +++ /dev/null @@ -1,106 +0,0 @@ -package net.pterodactylus.sone.core; - -import static java.util.Arrays.asList; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.never; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashSet; - -import net.pterodactylus.sone.core.SoneChangeDetector.PostProcessor; -import net.pterodactylus.sone.core.SoneChangeDetector.PostReplyProcessor; -import net.pterodactylus.sone.data.Post; -import net.pterodactylus.sone.data.PostReply; -import net.pterodactylus.sone.data.Sone; - -import org.junit.Before; -import org.junit.Test; - -/** - * Unit test for {@link SoneChangeDetector}. - */ -public class SoneChangeDetectorTest { - - private final Sone oldSone = mock(Sone.class); - private final Sone newSone = mock(Sone.class); - private final SoneChangeDetector soneChangeDetector = - new SoneChangeDetector(oldSone); - private final Post oldPost = mock(Post.class); - private final Post removedPost = mock(Post.class); - private final Post newPost = mock(Post.class); - private final PostProcessor newPostProcessor = mock(PostProcessor.class); - private final PostProcessor removedPostProcessor = - mock(PostProcessor.class); - private final PostReply oldPostReply = mock(PostReply.class); - private final PostReply removedPostReply = mock(PostReply.class); - private final PostReply newPostReply = mock(PostReply.class); - private final PostReplyProcessor newPostReplyProcessor = - mock(PostReplyProcessor.class); - private final PostReplyProcessor removedPostReplyProcessor = - mock(PostReplyProcessor.class); - - @Before - public void setupPosts() { - when(oldSone.getPosts()).thenReturn(asList(oldPost, removedPost)); - when(newSone.getPosts()).thenReturn(asList(oldPost, newPost)); - } - - @Before - public void setupPostProcessors() { - soneChangeDetector.onNewPosts(newPostProcessor); - soneChangeDetector.onRemovedPosts(removedPostProcessor); - } - - @Before - public void setupPostReplies() { - when(oldSone.getReplies()).thenReturn( - new HashSet( - asList(oldPostReply, removedPostReply))); - when(newSone.getReplies()).thenReturn( - new HashSet(asList(oldPostReply, newPostReply))); - } - - @Before - public void setupPostReplyProcessors() { - soneChangeDetector.onNewPostReplies(newPostReplyProcessor); - soneChangeDetector.onRemovedPostReplies(removedPostReplyProcessor); - } - - @Test - public void changeDetectorDetectsChanges() { - soneChangeDetector.detectChanges(newSone); - - verify(newPostProcessor).processPost(newPost); - verify(newPostProcessor, never()).processPost(oldPost); - verify(newPostProcessor, never()).processPost(removedPost); - verify(removedPostProcessor).processPost(removedPost); - verify(removedPostProcessor, never()).processPost(oldPost); - verify(removedPostProcessor, never()).processPost(newPost); - - verify(newPostReplyProcessor).processPostReply(newPostReply); - verify(newPostReplyProcessor, never()).processPostReply(oldPostReply); - verify(newPostReplyProcessor, never()).processPostReply( - removedPostReply); - verify(removedPostReplyProcessor).processPostReply(removedPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - oldPostReply); - verify(removedPostReplyProcessor, never()).processPostReply( - newPostReply); - } - - @Test - public void changeDetectorDoesNotNotifyAnyProcessorIfProcessorsUnset() { - soneChangeDetector.onNewPosts(null); - soneChangeDetector.onRemovedPosts(null); - soneChangeDetector.onNewPostReplies(null); - soneChangeDetector.onRemovedPostReplies(null); - soneChangeDetector.detectChanges(newSone); - verify(newPostProcessor, never()).processPost(any(Post.class)); - verify(removedPostProcessor, never()).processPost(any(Post.class)); - verify(newPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - verify(removedPostReplyProcessor, never()).processPostReply(any(PostReply.class)); - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt new file mode 100644 index 0000000..f4f4818 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/PreferencesTest.kt @@ -0,0 +1,326 @@ +package net.pterodactylus.sone.core + +import com.google.common.eventbus.* +import net.pterodactylus.sone.core.event.* +import net.pterodactylus.sone.fcp.FcpInterface.* +import net.pterodactylus.sone.fcp.FcpInterface.FullAccessRequired.* +import net.pterodactylus.sone.fcp.event.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* +import org.mockito.ArgumentMatchers.any +import org.mockito.Mockito.atLeastOnce +import org.mockito.Mockito.never +import org.mockito.Mockito.verify + +/** + * Unit test for [Preferences]. + */ +class PreferencesTest { + + private val eventBus = mock() + private val preferences = Preferences(eventBus) + private val eventsCaptor = capture() + + @Test + fun `preferences retain insertion delay`() { + preferences.insertionDelay = 15 + assertThat(preferences.insertionDelay, equalTo(15)) + } + + @Test + fun `preferences sends event on setting insertion delay`() { + preferences.insertionDelay = 15 + verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()) + assertThat(eventsCaptor.allValues, hasItem(InsertionDelayChangedEvent(15))) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid insertion delay is rejected`() { + preferences.insertionDelay = -15 + } + + @Test + fun `no event is sent when invalid insertion delay is set`() { + try { + preferences.insertionDelay = -15 + } catch (iae: IllegalArgumentException) { + /* ignore. */ + } + + verify(eventBus, never()).post(any()) + } + + @Test + fun `preferences return default value when insertion delay is set to null`() { + preferences.setInsertionDelay(null) + assertThat(preferences.insertionDelay, equalTo(60)) + } + + @Test + fun `preferences start with insertion delay default value`() { + assertThat(preferences.insertionDelay, equalTo(60)) + } + + @Test + fun `preferences retain posts per page`() { + preferences.postsPerPage = 15 + assertThat(preferences.postsPerPage, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid posts per page is rejected`() { + preferences.postsPerPage = -15 + } + + @Test + fun `preferences return default value when posts per page is set to null`() { + preferences.setPostsPerPage(null) + assertThat(preferences.postsPerPage, equalTo(10)) + } + + @Test + fun `preferences start with posts per page default value`() { + assertThat(preferences.postsPerPage, equalTo(10)) + } + + @Test + fun `preferences retain images per page`() { + preferences.imagesPerPage = 15 + assertThat(preferences.imagesPerPage, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid images per page is rejected`() { + preferences.imagesPerPage = -15 + } + + @Test + fun `preferences return default value when images per page is set to null`() { + preferences.setImagesPerPage(null) + assertThat(preferences.imagesPerPage, equalTo(9)) + } + + @Test + fun `preferences start with images per page default value`() { + assertThat(preferences.imagesPerPage, equalTo(9)) + } + + @Test + fun `preferences retain characters per post`() { + preferences.charactersPerPost = 150 + assertThat(preferences.charactersPerPost, equalTo(150)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid characters per post is rejected`() { + preferences.charactersPerPost = -15 + } + + @Test + fun `preferences return default value when characters per post is set to null`() { + preferences.setCharactersPerPost(null) + assertThat(preferences.charactersPerPost, equalTo(400)) + } + + @Test + fun `preferences start with characters per post default value`() { + assertThat(preferences.charactersPerPost, equalTo(400)) + } + + @Test + fun `preferences retain post cut off length`() { + preferences.postCutOffLength = 150 + assertThat(preferences.postCutOffLength, equalTo(150)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid post cut off length is rejected`() { + preferences.postCutOffLength = -15 + } + + @Test(expected = IllegalArgumentException::class) + fun `cut off length of minus one is not allowed`() { + preferences.postCutOffLength = -1 + } + + @Test + fun `preferences return default value when post cut off length is set to null`() { + preferences.setPostCutOffLength(null) + assertThat(preferences.postCutOffLength, equalTo(200)) + } + + @Test + fun `preferences start with post cut off length default value`() { + assertThat(preferences.postCutOffLength, equalTo(200)) + } + + @Test + fun `preferences retain require full access of true`() { + preferences.isRequireFullAccess = true + assertThat(preferences.isRequireFullAccess, equalTo(true)) + } + + @Test + fun `preferences retain require full access of false`() { + preferences.isRequireFullAccess = false + assertThat(preferences.isRequireFullAccess, equalTo(false)) + } + + @Test + fun `preferences return default value when require full access is set to null`() { + preferences.setRequireFullAccess(null) + assertThat(preferences.isRequireFullAccess, equalTo(false)) + } + + @Test + fun `preferences start with require full access default value`() { + assertThat(preferences.isRequireFullAccess, equalTo(false)) + } + + @Test + fun `preferences retain positive trust`() { + preferences.positiveTrust = 15 + assertThat(preferences.positiveTrust, equalTo(15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid positive trust is rejected`() { + preferences.positiveTrust = -15 + } + + @Test + fun `preferences return default value when positive trust is set to null`() { + preferences.setPositiveTrust(null) + assertThat(preferences.positiveTrust, equalTo(75)) + } + + @Test + fun `preferences start with positive trust default value`() { + assertThat(preferences.positiveTrust, equalTo(75)) + } + + @Test + fun `preferences retain negative trust`() { + preferences.negativeTrust = -15 + assertThat(preferences.negativeTrust, equalTo(-15)) + } + + @Test(expected = IllegalArgumentException::class) + fun `invalid negative trust is rejected`() { + preferences.negativeTrust = 150 + } + + @Test + fun `preferences return default value when negative trust is set to null`() { + preferences.setNegativeTrust(null) + assertThat(preferences.negativeTrust, equalTo(-25)) + } + + @Test + fun `preferences start with negative trust default value`() { + assertThat(preferences.negativeTrust, equalTo(-25)) + } + + @Test + fun `preferences retain trust comment`() { + preferences.trustComment = "Trust" + assertThat(preferences.trustComment, equalTo("Trust")) + } + + @Test + fun `preferences return default value when trust comment is set to null`() { + preferences.trustComment = null + assertThat(preferences.trustComment, + equalTo("Set from Sone Web Interface")) + } + + @Test + fun `preferences start with trust comment default value`() { + assertThat(preferences.trustComment, + equalTo("Set from Sone Web Interface")) + } + + @Test + fun `preferences retain fcp interface active of true`() { + preferences.isFcpInterfaceActive = true + assertThat(preferences.isFcpInterfaceActive, equalTo(true)) + verify(eventBus).post(any(FcpInterfaceActivatedEvent::class.java)) + } + + @Test + fun `preferences retain fcp interface active of false`() { + preferences.isFcpInterfaceActive = false + assertThat(preferences.isFcpInterfaceActive, equalTo(false)) + verify(eventBus).post(any(FcpInterfaceDeactivatedEvent::class.java)) + } + + @Test + fun `preferences return default value when fcp interface active is set to null`() { + preferences.setFcpInterfaceActive(null) + assertThat(preferences.isFcpInterfaceActive, equalTo(false)) + verify(eventBus).post(any(FcpInterfaceDeactivatedEvent::class.java)) + } + + @Test + fun `preferences start with fcp interface active default value`() { + assertThat(preferences.isFcpInterfaceActive, equalTo(false)) + } + + @Test + fun `preferences retain fcp full access required of no`() { + preferences.fcpFullAccessRequired = NO + assertThat(preferences.fcpFullAccessRequired, equalTo(NO)) + verifyFullAccessRequiredChangedEvent(NO) + } + + private fun verifyFullAccessRequiredChangedEvent( + fullAccessRequired: FullAccessRequired) { + verify(eventBus).post(eventsCaptor.capture()) + assertThat(eventsCaptor.value, instanceOf(FullAccessRequiredChanged::class.java)) + assertThat((eventsCaptor.value as FullAccessRequiredChanged).fullAccessRequired, + equalTo(fullAccessRequired)) + } + + @Test + fun `preferences retain fcp full access required of writing`() { + preferences.fcpFullAccessRequired = WRITING + assertThat(preferences.fcpFullAccessRequired, equalTo(WRITING)) + verifyFullAccessRequiredChangedEvent(WRITING) + } + + @Test + fun `preferences retain fcp full access required of always`() { + preferences.fcpFullAccessRequired = ALWAYS + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + verifyFullAccessRequiredChangedEvent(ALWAYS) + } + + @Test + fun `preferences return default value when fcp full access required is set to null`() { + preferences.fcpFullAccessRequired = null + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + verifyFullAccessRequiredChangedEvent(ALWAYS) + } + + @Test + fun `preferences start with fcp full access required default value`() { + assertThat(preferences.fcpFullAccessRequired, equalTo(ALWAYS)) + } + + @Test + fun `setting insertion delay to valid value sends change event`() { + preferences.insertionDelay = 30 + verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()) + assertThat(eventsCaptor.allValues, hasItem(PreferenceChangedEvent("InsertionDelay", 30))) + } + + @Test + fun `setting posts per page to valid value sends change event`() { + preferences.postsPerPage = 30 + verify(eventBus, atLeastOnce()).post(eventsCaptor.capture()) + assertThat(eventsCaptor.allValues, hasItem(PreferenceChangedEvent("PostsPerPage", 30))) + } + +} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt deleted file mode 100644 index 3b82b49..0000000 --- a/src/test/kotlin/net/pterodactylus/sone/core/SoneChangeCollectorTest.kt +++ /dev/null @@ -1,78 +0,0 @@ -package net.pterodactylus.sone.core - -import net.pterodactylus.sone.data.Post -import net.pterodactylus.sone.data.PostReply -import net.pterodactylus.sone.data.Sone -import net.pterodactylus.sone.test.mock -import net.pterodactylus.sone.test.whenever -import org.hamcrest.MatcherAssert.assertThat -import org.hamcrest.Matchers.containsInAnyOrder -import org.hamcrest.Matchers.emptyIterable -import org.hamcrest.Matchers.equalTo -import org.junit.Test -import java.util.concurrent.atomic.AtomicInteger - -/** - * Unit test for [SoneChangeCollectorTest]. - */ -class SoneChangeCollectorTest { - - private val oldSone = mock() - private val newSone = mock() - private val changeCollector = SoneChangeCollector(oldSone) - - @Test - fun `new posts are correctly turned into events`() { - val posts = listOf(mock(), mock(), mock()) - whenever(newSone.posts).thenReturn(posts) - changeCollector.newPostEvent { it.takeIf { it != posts[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(posts[0], posts[2])) - } - - @Test - fun `actions can be performed on new post without being returned`() { - val posts = listOf(mock(), mock(), mock()) - val counter = AtomicInteger(0) - whenever(newSone.posts).thenReturn(posts.slice(0..2)) - whenever(oldSone.posts).thenReturn(posts.slice(2..2)) - changeCollector.onNewPost { counter.incrementAndGet() } - assertThat(changeCollector.detectChanges(newSone), emptyIterable()) - assertThat(counter.get(), equalTo(2)) - } - - @Test - fun `removed posts are correctly turned into events`() { - val posts = listOf(mock(), mock(), mock()) - whenever(oldSone.posts).thenReturn(posts) - changeCollector.removedPostEvent { it.takeIf { it != posts[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(posts[0], posts[2])) - } - - @Test - fun `new post replies are correctly turned into events`() { - val postReplies = listOf(mock(), mock(), mock()) - whenever(newSone.replies).thenReturn(postReplies.toSet()) - changeCollector.newPostReplyEvent { it.takeIf { it != postReplies[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(postReplies[0], postReplies[2])) - } - - @Test - fun `actions can be performed on new replies without being returned`() { - val replies = listOf(mock(), mock(), mock()) - val counter = AtomicInteger(0) - whenever(newSone.replies).thenReturn(replies.slice(0..2).toSet()) - whenever(oldSone.replies).thenReturn(replies.slice(2..2).toSet()) - changeCollector.onNewPostReply { counter.incrementAndGet() } - assertThat(changeCollector.detectChanges(newSone), emptyIterable()) - assertThat(counter.get(), equalTo(2)) - } - - @Test - fun `removed post replies are correctly turned into events`() { - val postReplies = listOf(mock(), mock(), mock()) - whenever(oldSone.replies).thenReturn(postReplies.toSet()) - changeCollector.onRemovedPostReply { it.takeIf { it != postReplies[1] } } - assertThat(changeCollector.detectChanges(newSone), containsInAnyOrder(postReplies[0], postReplies[2])) - } - -} diff --git a/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt new file mode 100644 index 0000000..f79d736 --- /dev/null +++ b/src/test/kotlin/net/pterodactylus/sone/core/SoneComparisonTest.kt @@ -0,0 +1,50 @@ +package net.pterodactylus.sone.core + +import net.pterodactylus.sone.data.* +import net.pterodactylus.sone.test.* +import org.hamcrest.MatcherAssert.* +import org.hamcrest.Matchers.* +import org.junit.* + +class SoneComparsisonTest { + + private val oldSone = mock() + private val newSone = mock() + + private val oldPost = mock() + private val removedPost = mock() + private val newPost = mock() + private val oldPostReply = mock() + private val removedPostReply = mock() + private val newPostReply = mock() + + init { + whenever(oldSone.posts).thenReturn(listOf(oldPost, removedPost)) + whenever(newSone.posts).thenReturn(listOf(oldPost, newPost)) + whenever(oldSone.replies).thenReturn(setOf(oldPostReply, removedPostReply)) + whenever(newSone.replies).thenReturn(setOf(oldPostReply, newPostReply)) + } + + private val soneComparison = SoneComparison(oldSone, newSone) + + @Test + fun `new posts are identified correctly`() { + assertThat(soneComparison.newPosts, contains(newPost)) + } + + @Test + fun `removed posts are identified correctly`() { + assertThat(soneComparison.removedPosts, contains(removedPost)) + } + + @Test + fun `new post replies are identified correctly`() { + assertThat(soneComparison.newPostReplies, contains(newPostReply)) + } + + @Test + fun `removed post replies are identified correctly`() { + assertThat(soneComparison.removedPostReplies, contains(removedPostReply)) + } + +}