1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
package social.grain
import androidx.test.ext.junit.runners.AndroidJUnit4
import kotlinx.coroutines.runBlocking
import kotlinx.serialization.json.Json
import okhttp3.OkHttpClient
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
import social.grain.data.api.XrpcClient
import social.grain.data.api.getCommentThread
import social.grain.data.api.getFeed
import social.grain.data.api.getGallery
import social.grain.data.auth.AuthManager
import java.util.concurrent.TimeUnit
/**
* Decodes live gallery-detail and comment responses into the ported models.
*
* Same class of risk the feed models carried: a field typed wrong here shows up
* only as an empty comment sheet with a decode error buried in the log.
*/
@RunWith(AndroidJUnit4::class)
class CommentDecodeTest {
private val client = XrpcClient(
baseUrl = AuthManager.SERVER_URL,
http = OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build(),
json = Json {
ignoreUnknownKeys = true
explicitNulls = false
coerceInputValues = true
},
)
@Test
fun galleryDetailDecodesForARealGallery() = runBlocking {
val uri = client.getFeed(feed = "recent", limit = 1).items.orEmpty().first().uri
val gallery = client.getGallery(uri).gallery
assertEquals(uri, gallery.uri)
assertTrue("Creator DID missing", gallery.creator.did.startsWith("did:"))
assertTrue("Detail returned no photos", gallery.items.orEmpty().isNotEmpty())
}
@Test
fun commentThreadDecodesAndRepliesNameTheirRoot() = runBlocking {
// Walk the feed for a gallery that actually has comments rather than
// asserting against whatever happens to be newest.
val withComments = client.getFeed(feed = "recent", limit = 60).items.orEmpty()
.firstOrNull { (it.commentCount ?: 0) > 0 }
if (withComments == null) {
// Nothing to assert against; still exercise the decode path so a
// broken response type fails rather than silently skipping.
client.getCommentThread(client.getFeed(feed = "recent", limit = 1).items!!.first().uri)
return@runBlocking
}
val thread = client.getCommentThread(withComments.uri)
assertTrue("Gallery reported comments but the thread was empty", thread.comments.isNotEmpty())
val uris = thread.comments.map { it.uri }.toSet()
for (comment in thread.comments) {
assertTrue("Comment URI should be an at:// URI", comment.uri.startsWith("at://"))
assertTrue("Comment author DID missing", comment.author.did.startsWith("did:"))
comment.replyTo?.let {
assertTrue("replyTo should be an at:// URI, was '$it'", it.startsWith("at://"))
}
// Exercise the facet path against whatever real records contain.
comment.facets?.forEach { it.parsedFeatures }
}
assertEquals("Comment URIs should be unique", thread.comments.size, uris.size)
}
}