🎨 Replace reply comparator with Kotlin version
authorDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 22 Feb 2020 22:37:38 +0000 (23:37 +0100)
committerDavid ‘Bombe’ Roden <bombe@pterodactylus.net>
Sat, 22 Feb 2020 23:15:07 +0000 (00:15 +0100)
src/main/java/net/pterodactylus/sone/core/SoneInserter.java
src/main/java/net/pterodactylus/sone/data/Reply.java
src/main/java/net/pterodactylus/sone/data/impl/SoneImpl.java
src/main/kotlin/net/pterodactylus/sone/data/Reply.kt [new file with mode: 0644]
src/main/kotlin/net/pterodactylus/sone/database/memory/MemoryDatabase.kt
src/test/kotlin/net/pterodactylus/sone/data/ReplyTest.kt [new file with mode: 0644]
src/test/kotlin/net/pterodactylus/sone/test/Mocks.kt

index ffbed4d..670b2c8 100644 (file)
@@ -23,6 +23,7 @@ import static java.util.concurrent.TimeUnit.*;
 import static java.util.logging.Logger.getLogger;
 import static java.util.stream.Collectors.toList;
 import static net.pterodactylus.sone.data.PostKt.newestPostFirst;
+import static net.pterodactylus.sone.data.ReplyKt.newestReplyFirst;
 
 import java.io.*;
 import java.nio.charset.Charset;
@@ -310,7 +311,7 @@ public class SoneInserter extends AbstractService {
                        soneProperties.put("time", currentTimeMillis());
                        soneProperties.put("profile", sone.getProfile());
                        soneProperties.put("posts", Ordering.from(newestPostFirst()).sortedCopy(sone.getPosts()));
-                       soneProperties.put("replies", Ordering.from(Reply.TIME_COMPARATOR).reverse().sortedCopy(sone.getReplies()));
+                       soneProperties.put("replies", Ordering.from(newestReplyFirst()).sortedCopy(sone.getReplies()));
                        soneProperties.put("likedPostIds", new HashSet<>(sone.getLikedPostIds()));
                        soneProperties.put("likedReplyIds", new HashSet<>(sone.getLikedReplyIds()));
                        soneProperties.put("albums", SoneKt.getAllAlbums(sone).stream().filter(AlbumKt.notEmpty()::invoke).collect(toList()));
index 120575e..705b1e4 100644 (file)
@@ -29,19 +29,6 @@ import com.google.common.base.Predicate;
  */
 public interface Reply<T extends Reply<T>> extends Identified {
 
-       /** Comparator that sorts replies ascending by time. */
-       public static final Comparator<? super Reply<?>> TIME_COMPARATOR = new Comparator<Reply<?>>() {
-
-               /**
-                * {@inheritDoc}
-                */
-               @Override
-               public int compare(Reply<?> leftReply, Reply<?> rightReply) {
-                       return (int) Math.max(Integer.MIN_VALUE, Math.min(Integer.MAX_VALUE, leftReply.getTime() - rightReply.getTime()));
-               }
-
-       };
-
        /** Filter for replies with timestamps from the future. */
        public static final Predicate<Reply<?>> FUTURE_REPLY_FILTER = new Predicate<Reply<?>>() {
 
index 9baaba9..a197c46 100644 (file)
@@ -22,6 +22,7 @@ import static java.lang.String.format;
 import static java.nio.charset.StandardCharsets.UTF_8;
 import static java.util.logging.Logger.getLogger;
 import static net.pterodactylus.sone.data.PostKt.newestPostFirst;
+import static net.pterodactylus.sone.data.ReplyKt.newestReplyFirst;
 import static net.pterodactylus.sone.data.SoneKt.*;
 
 import java.net.MalformedURLException;
@@ -626,7 +627,7 @@ public class SoneImpl implements Sone {
                hash.putString(")", UTF_8);
 
                List<PostReply> replies = new ArrayList<>(getReplies());
-               Collections.sort(replies, Reply.TIME_COMPARATOR);
+               replies.sort(newestReplyFirst().reversed());
                hash.putString("Replies(", UTF_8);
                for (PostReply reply : replies) {
                        hash.putString("Reply(", UTF_8).putString(reply.getId(), UTF_8).putString(")", UTF_8);
diff --git a/src/main/kotlin/net/pterodactylus/sone/data/Reply.kt b/src/main/kotlin/net/pterodactylus/sone/data/Reply.kt
new file mode 100644 (file)
index 0000000..9a3ec64
--- /dev/null
@@ -0,0 +1,27 @@
+/**
+ * Sone - Reply.kt - Copyright Â© 2020 David â€˜Bombe’ Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data
+
+import java.util.Comparator.comparing
+
+/**
+ * Comparator that orders replies by their time, newest replies first.
+ */
+@get:JvmName("newestReplyFirst")
+val newestReplyFirst: Comparator<Reply<*>> =
+               comparing(Reply<*>::getTime).reversed()
index 5c32486..e943b38 100644 (file)
@@ -28,12 +28,12 @@ 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.Reply.TIME_COMPARATOR
 import net.pterodactylus.sone.data.Sone
 import net.pterodactylus.sone.data.allAlbums
 import net.pterodactylus.sone.data.allImages
 import net.pterodactylus.sone.data.impl.AlbumBuilderImpl
 import net.pterodactylus.sone.data.impl.ImageBuilderImpl
+import net.pterodactylus.sone.data.newestReplyFirst
 import net.pterodactylus.sone.database.AlbumBuilder
 import net.pterodactylus.sone.database.Database
 import net.pterodactylus.sone.database.DatabaseException
@@ -62,7 +62,7 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
        private val sonePosts: Multimap<String, Post> = HashMultimap.create<String, Post>()
        private val knownPosts = mutableSetOf<String>()
        private val allPostReplies = mutableMapOf<String, PostReply>()
-       private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, TIME_COMPARATOR)
+       private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, newestReplyFirst)
        private val knownPostReplies = mutableSetOf<String>()
        private val allAlbums = mutableMapOf<String, Album>()
        private val soneAlbums: Multimap<String, Album> = HashMultimap.create<String, Album>()
@@ -227,7 +227,7 @@ class MemoryDatabase @Inject constructor(private val configuration: Configuratio
                        readLock.withLock {
                                allPostReplies.values
                                                .filter { it.postId == postId }
-                                               .sortedWith(TIME_COMPARATOR)
+                                               .sortedWith(newestReplyFirst.reversed())
                        }
 
        override fun newPostReplyBuilder(): PostReplyBuilder =
diff --git a/src/test/kotlin/net/pterodactylus/sone/data/ReplyTest.kt b/src/test/kotlin/net/pterodactylus/sone/data/ReplyTest.kt
new file mode 100644 (file)
index 0000000..3289b7d
--- /dev/null
@@ -0,0 +1,50 @@
+/**
+ * Sone - ReplyTest.kt - Copyright Â© 2020 David â€˜Bombe’ Roden
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+package net.pterodactylus.sone.data
+
+import net.pterodactylus.sone.test.emptyPostReply
+import org.hamcrest.MatcherAssert.assertThat
+import org.hamcrest.Matchers.equalTo
+import org.hamcrest.Matchers.greaterThan
+import org.hamcrest.Matchers.lessThan
+import kotlin.test.Test
+
+class ReplyTest {
+
+       @Test
+       fun `newestReplyFirst comparator returns less-than 0 is first reply is newer than second`() {
+               val newerReply = emptyPostReply(time = 2000)
+               val olderReply = emptyPostReply(time = 1000)
+               assertThat(newestReplyFirst.compare(newerReply, olderReply), lessThan(0))
+       }
+
+       @Test
+       fun `newestReplyFirst comparator returns greater-than 0 is first reply is older than second`() {
+               val newerReply = emptyPostReply(time = 2000)
+               val olderReply = emptyPostReply(time = 1000)
+               assertThat(newestReplyFirst.compare(olderReply, newerReply), greaterThan(0))
+       }
+
+       @Test
+       fun `newestReplyFirst comparator returns 0 is first and second reply have same age`() {
+               val reply1 = emptyPostReply(time = 1000)
+               val reply2 = emptyPostReply(time = 1000)
+               assertThat(newestReplyFirst.compare(reply1, reply2), equalTo(0))
+       }
+
+}
index 17eae9a..ae2ecd6 100644 (file)
@@ -52,12 +52,12 @@ fun createPost(text: String = "", sone: Sone = remoteSone1, known: Boolean = fal
        }
 }
 
-fun emptyPostReply(text: String = "", post: Post? = createPost(), sone: Sone = remoteSone1, known: Boolean = false) = object : PostReply {
+fun emptyPostReply(text: String = "", post: Post? = createPost(), sone: Sone = remoteSone1, known: Boolean = false, time: Long = 1) = object : PostReply {
        override val id = "reply-id"
        override fun getSone() = sone
        override fun getPostId() = post!!.id
        override fun getPost(): Optional<Post> = Optional.fromNullable(post)
-       override fun getTime() = 1L
+       override fun getTime() = time
        override fun getText() = text
        override fun isKnown() = known
        override fun setKnown(known: Boolean): PostReply = this