Return a nullable PostReply instead of an Optional
[Sone.git] / src / test / kotlin / net / pterodactylus / sone / fcp / SoneCommandTest.kt
1 package net.pterodactylus.sone.fcp
2
3 import com.google.common.base.Optional.absent
4 import freenet.support.SimpleFieldSet
5 import net.pterodactylus.sone.core.Core
6 import net.pterodactylus.sone.data.Post
7 import net.pterodactylus.sone.data.PostReply
8 import net.pterodactylus.sone.data.Profile
9 import net.pterodactylus.sone.data.Sone
10 import net.pterodactylus.sone.freenet.fcp.FcpException
11 import net.pterodactylus.sone.template.SoneAccessor
12 import net.pterodactylus.sone.test.OneByOneMatcher
13 import net.pterodactylus.sone.test.mock
14 import net.pterodactylus.sone.test.whenever
15 import net.pterodactylus.sone.utils.asOptional
16 import org.junit.Before
17 import org.junit.Rule
18 import org.junit.rules.ExpectedException
19 import org.mockito.ArgumentMatchers.anyString
20
21 /**
22  * Base class for Sone FCP command tests.
23  */
24 abstract class SoneCommandTest {
25
26         @Rule @JvmField val expectedException = ExpectedException.none()!!
27
28         protected val core = mock<Core>()
29         protected val command: AbstractSoneCommand by lazy { createCommand(core) }
30
31         protected val parameters = SimpleFieldSet(true)
32         protected val localSone = mock<Sone>().apply {
33                 whenever(isLocal).thenReturn(true)
34         }
35         protected val remoteSone = mock<Sone>()
36
37         protected abstract fun createCommand(core: Core): AbstractSoneCommand
38
39         @Before
40         fun setupCore() {
41                 whenever(core.getSone(anyString())).thenReturn(null)
42                 whenever(core.getPost(anyString())).thenReturn(absent())
43                 whenever(core.getPostReply(anyString())).thenReturn(null)
44         }
45
46         protected fun createSone(id: String, name: String, firstName: String, lastName: String, time: Long) = mock<Sone>().apply {
47                 whenever(this.id).thenReturn(id)
48                 whenever(this.name).thenReturn(name)
49                 whenever(profile).thenReturn(Profile(this).apply {
50                         this.firstName = firstName
51                         this.lastName = lastName
52                 })
53                 whenever(this.time).thenReturn(time)
54         }
55
56         protected fun createPost(id: String, sone: Sone, recipientId: String?, time: Long, text: String) = mock<Post>().apply {
57                 whenever(this.id).thenReturn(id)
58                 whenever(this.sone).thenReturn(sone)
59                 whenever(this.recipientId).thenReturn(recipientId.asOptional())
60                 whenever(this.time).thenReturn(time)
61                 whenever(this.text).thenReturn(text)
62         }
63
64         protected fun createReply(id: String, sone: Sone, post: Post, time: Long, text: String) = mock<PostReply>().apply {
65                 whenever(this.id).thenReturn(id)
66                 whenever(this.sone).thenReturn(sone)
67                 whenever(this.post).thenReturn(post.asOptional())
68                 whenever(this.time).thenReturn(time)
69                 whenever(this.text).thenReturn(text)
70         }
71
72         protected fun executeCommandAndExpectFcpException() {
73                 expectedException.expect(FcpException::class.java)
74                 command.execute(parameters)
75         }
76
77         protected fun requestWithoutAnyParameterResultsInFcpException() {
78                 expectedException.expect(FcpException::class.java)
79                 command.execute(parameters)
80         }
81
82         protected fun requestWithEmptySoneParameterResultsInFcpException() {
83                 parameters += "Sone" to null
84                 executeCommandAndExpectFcpException()
85         }
86
87         protected fun requestWithInvalidSoneParameterResultsInFcpException() {
88                 parameters += "Sone" to "InvalidSoneId"
89                 executeCommandAndExpectFcpException()
90         }
91
92         fun requestWithValidRemoteSoneParameterResultsInFcpException() {
93                 parameters += "Sone" to "RemoteSoneId"
94                 whenever(core.getSone("RemoteSoneId")).thenReturn(remoteSone)
95                 executeCommandAndExpectFcpException()
96         }
97
98         protected operator fun SimpleFieldSet.plusAssign(keyValue: Pair<String, String?>) = putSingle(keyValue.first, keyValue.second)
99         protected fun SimpleFieldSet.parsePost(prefix: String) = parseFromSimpleFieldSet(prefix, "ID", "Sone", "Recipient", "Time", "Text")
100         protected fun SimpleFieldSet.parseReply(prefix: String) = parseFromSimpleFieldSet(prefix, "ID", "Sone", "Time", "Text")
101         protected fun SimpleFieldSet.parseSone(prefix: String) = parseFromSimpleFieldSet(prefix, "ID", "Name", "NiceName", "LastUpdated", "Followed") +
102                         (0 until this["${prefix}Field.Count"].toInt()).map {
103                                 ("Field." + this["${prefix}Field.$it.Name"]) to this["${prefix}Field.$it.Value"]
104                         }
105
106         private fun SimpleFieldSet.parseFromSimpleFieldSet(prefix: String, vararg fields: String): Map<String, String?> = fields
107                         .associate { it to get(prefix + it) }
108
109         protected fun matchesPost(post: Post) = OneByOneMatcher<Map<String, String?>>().apply {
110                 expect("ID", post.id) { it["ID"] }
111                 expect("Sone", post.sone.id) { it["Sone"] }
112                 expect("recipient", post.recipientId.orNull()) { it["Recipient"] }
113                 expect("time", post.time.toString()) { it["Time"] }
114                 expect("text", post.text.replace("\\", "\\\\").replace("\r", "\\r").replace("\n", "\\n")) { it["Text"] }
115         }
116
117         protected fun matchesReply(reply: PostReply) = OneByOneMatcher<Map<String, String?>>().apply {
118                 expect("ID", reply.id) { it["ID"] }
119                 expect("Sone", reply.sone.id) { it["Sone"] }
120                 expect("time", reply.time.toString()) { it["Time"] }
121                 expect("text", reply.text.replace("\\", "\\\\").replace("\r", "\\r").replace("\n", "\\n")) { it["Text"] }
122         }
123
124         protected fun matchesSone(sone: Sone) = OneByOneMatcher<Map<String, String?>>().apply {
125                 expect("ID", sone.id) { it["ID"] }
126                 expect("name", sone.name) { it["Name"] }
127                 expect("last updated", sone.time.toString()) { it["LastUpdated"] }
128                 expect("nice name", SoneAccessor.getNiceName(sone)) { it["NiceName"] }
129                 sone.profile.fields.forEach { field ->
130                         expect("field: ${field.name}", field.value) { it["Field.${field.name}"] }
131                 }
132         }
133
134 }