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;
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()));
*/
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<?>>() {
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;
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);
--- /dev/null
+/**
+ * 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()
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
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>()
readLock.withLock {
allPostReplies.values
.filter { it.postId == postId }
- .sortedWith(TIME_COMPARATOR)
+ .sortedWith(newestReplyFirst.reversed())
}
override fun newPostReplyBuilder(): PostReplyBuilder =
--- /dev/null
+/**
+ * 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))
+ }
+
+}
}
}
-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