private val writeLock: WriteLock by lazy { lock.writeLock() }
private val configurationLoader = ConfigurationLoader(configuration)
private val allSones = mutableMapOf<String, Sone>()
- private val allPosts = mutableMapOf<String, Post>()
- private val sonePosts: Multimap<String, Post> = HashMultimap.create<String, Post>()
+ private val allPosts = mutableMapOf<String, MemoryPost.Shell>()
+ private val sonePosts: Multimap<String, MemoryPost.Shell> = HashMultimap.create<String, MemoryPost.Shell>()
private val knownPosts = mutableSetOf<String>()
private val allPostReplies = mutableMapOf<String, MemoryPostReply.Shell>()
private val sonePostReplies: Multimap<String, PostReply> = TreeMultimap.create<String, PostReply>(Comparator { leftString, rightString -> leftString.compareTo(rightString) }, newestReplyFirst)
removeSone(sone)
allSones[sone.id] = sone
- sonePosts.putAll(sone.id, sone.posts)
- for (post in sone.posts) {
+ sonePosts.putAll(sone.id, sone.posts.map(Post::toShell))
+ for (post in sone.posts.map(Post::toShell)) {
allPosts[post.id] = post
}
sonePostReplies.putAll(sone.id, sone.replies)
override fun getFollowingTime(friendSoneId: String) =
memoryFriendDatabase.getFollowingTime(friendSoneId)
- override fun getPost(postId: String) =
- readLock.withLock { allPosts[postId] }
+ override fun getPost(postId: String): Post? =
+ readLock.withLock { allPosts[postId]?.build(newPostBuilder()) }
override fun getPosts(soneId: String): Collection<Post> =
- sonePosts[soneId].toSet()
+ sonePosts[soneId].map { it.build(newPostBuilder()) }.toSet()
override fun getDirectedPosts(recipientId: String) =
readLock.withLock {
- allPosts.values.filter {
- it.recipientId.orNull() == recipientId
- }
+ allPosts.values
+ .filter { it.recipientId == recipientId }
+ .map { it.build(newPostBuilder()) }
}
override fun newPostBuilder(): PostBuilder = MemoryPostBuilder(this, this)
override fun storePost(post: Post) {
checkNotNull(post, "post must not be null")
writeLock.withLock {
- allPosts[post.id] = post
- sonePosts[post.sone.id].add(post)
+ post.toShell().also { shell ->
+ allPosts[post.id] = shell
+ sonePosts[post.sone.id].add(shell)
+ }
}
}
checkNotNull(post, "post must not be null")
writeLock.withLock {
allPosts.remove(post.id)
- sonePosts[post.sone.id].remove(post)
+ sonePosts[post.sone.id].remove(post.toShell())
post.sone.removePost(post)
}
}
import net.pterodactylus.sone.data.Post
import net.pterodactylus.sone.data.Sone
+import net.pterodactylus.sone.database.PostBuilder
import net.pterodactylus.sone.database.SoneProvider
import net.pterodactylus.sone.utils.asOptional
* A post is a short message that a user writes in his Sone to let other users
* know what is going on.
*/
-internal class MemoryPost(
+class MemoryPost(
private val postDatabase: MemoryDatabase,
private val soneProvider: SoneProvider,
override val id: String,
override fun toString() = "${javaClass.name}[id=$id,sone=$soneId,recipient=$recipientId,time=$time,text=$text]"
+ data class Shell(val id: String, val soneId: String, val recipientId: String?, val time: Long, val text: String) {
+
+ fun build(postBuilder: PostBuilder) =
+ postBuilder.withId(id).from(soneId).let { if (recipientId != null) it.to(recipientId) else it }.withTime(time).withText(text).build()
+
+ }
+
}
+
+fun Post.toShell() = MemoryPost.Shell(id, sone!!.id, recipient.orNull()?.id, time, text)
@Test
fun `post recipients are detected correctly`() {
- val postWithRecipient = createPost(of(RECIPIENT_ID))
+ val postWithRecipient = createPost(id = "p1", recipient = createRemoteSone(RECIPIENT_ID))
memoryDatabase.storePost(postWithRecipient)
- val postWithoutRecipient = createPost(absent())
+ val postWithoutRecipient = createPost(id = "p2", recipient = null)
memoryDatabase.storePost(postWithoutRecipient)
- assertThat(memoryDatabase.getDirectedPosts(RECIPIENT_ID), contains(postWithRecipient))
- }
-
- private fun createPost(recipient: Optional<String>): Post {
- val postWithRecipient = mock<Post>()
- whenever(postWithRecipient.id).thenReturn(randomUUID().toString())
- whenever(postWithRecipient.sone).thenReturn(sone)
- whenever(postWithRecipient.recipientId).thenReturn(recipient)
- return postWithRecipient
+ assertThat(memoryDatabase.getDirectedPosts(RECIPIENT_ID), contains(isPost(isRecipientId = equalTo(RECIPIENT_ID))))
}
@Test
fun `post replies are managed correctly`() {
- val firstPost = createPost(absent())
+ val firstPost = createPost()
val firstPostFirstReply = createPostReply(id = "p1r1", post = firstPost, time = 1000L)
- val secondPost = createPost(absent())
+ val secondPost = createPost()
val secondPostFirstReply = createPostReply(id = "p2r1", post = secondPost, time = 1000L)
val secondPostSecondReply = createPostReply(id = "p2r2", post = secondPost, time = 2000L)
memoryDatabase.storePost(firstPost)
package net.pterodactylus.sone.test
import freenet.support.*
+import net.pterodactylus.sone.data.Post
import net.pterodactylus.sone.freenet.wot.*
import net.pterodactylus.sone.utils.*
import net.pterodactylus.util.web.*
}
}
+fun isPost(isRecipientId: Matcher<String?> = any(String::class.java)) = AttributeMatcher<Post>("post")
+ .addAttribute("recipient ID", { it.recipientId.orNull() }, isRecipientId)
+
/**
* [TypeSafeDiagnosingMatcher] implementation that aims to cut down boilerplate on verifying the attributes
* of typical container objects.
import net.pterodactylus.sone.freenet.wot.OwnIdentity
import net.pterodactylus.sone.utils.asFreenetBase64
import net.pterodactylus.sone.utils.asOptional
+import java.util.UUID
val remoteSone1 = createRemoteSone()
val remoteSone2 = createRemoteSone()
override fun getIdentity(): Identity = identity
}
-fun createPost(text: String = "", sone: Sone? = remoteSone1, known: Boolean = false, time: Long = 1, loaded: Boolean = true, recipient: Sone? = null): Post {
- return object : Post.EmptyPost("post-id") {
+fun createPost(text: String = "text", sone: Sone? = remoteSone1, known: Boolean = false, time: Long = 1, loaded: Boolean = true, recipient: Sone? = null, id: String = UUID.randomUUID().toString()): Post {
+ return object : Post.EmptyPost(id) {
override fun getRecipientId() = recipient?.id.asOptional()
override fun getRecipient() = recipient.asOptional()
override fun getSone() = sone
package net.pterodactylus.sone.test
-import com.google.common.base.Optional
import net.pterodactylus.sone.data.Post
-import net.pterodactylus.sone.data.Sone
import net.pterodactylus.sone.database.PostBuilder
import java.util.UUID
*/
class TestPostBuilder : PostBuilder {
- private val post = mock<Post>()
+ private var id: String? = null
+ private var soneId: String? = null
private var recipientId: String? = null
+ private var time: Long? = null
+ private var text: String? = null
override fun copyPost(post: Post): PostBuilder = this
override fun from(senderId: String): PostBuilder = apply {
- val sone = mock<Sone>()
- whenever(sone.id).thenReturn(senderId)
- whenever(post.sone).thenReturn(sone)
+ soneId = senderId
}
override fun randomId(): PostBuilder = apply {
- whenever(post.id).thenReturn(UUID.randomUUID().toString())
+ id = UUID.randomUUID().toString()
}
override fun withId(id: String): PostBuilder = apply {
- whenever(post.id).thenReturn(id)
+ this.id = id
}
override fun currentTime(): PostBuilder = apply {
- whenever(post.time).thenReturn(System.currentTimeMillis())
+ time = System.currentTimeMillis()
}
override fun withTime(time: Long): PostBuilder = apply {
- whenever(post.time).thenReturn(time)
+ this.time = time
}
override fun withText(text: String): PostBuilder = apply {
- whenever(post.text).thenReturn(text)
+ this.text = text
}
override fun to(recipientId: String): PostBuilder = apply {
this.recipientId = recipientId
}
- override fun build(): Post = post
- .also {
- whenever(post.recipientId).thenReturn(Optional.fromNullable(recipientId))
- }
+ override fun build(): Post =
+ createPost(text!!, sone = createRemoteSone(soneId!!), time = time!!, recipient = recipientId?.let { createRemoteSone(it) }, id = id!!)
}