Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
4.4 kB · 114 lines
Kotlin
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115package social.grain
import androidx.test.ext.junit.runners.AndroidJUnit4import kotlinx.coroutines.runBlockingimport kotlinx.serialization.json.Jsonimport okhttp3.OkHttpClientimport org.junit.Assert.assertFalseimport org.junit.Assert.assertNotNullimport org.junit.Assert.assertTrueimport org.junit.Testimport org.junit.runner.RunWithimport social.grain.data.api.XrpcClientimport social.grain.data.api.getActorProfileimport social.grain.data.api.getFeedimport social.grain.data.auth.AuthManagerimport java.util.concurrent.TimeUnit
/** * Decodes live appview responses into the ported model types. * * The models were transcribed from Swift structs, and a field typed `Int` that * the server actually sends as a string — or a required field the server omits * — fails only at runtime, on a real response, as an empty feed with a decode * error in the log. Reading it off the wire is the only way to know. */@RunWith(AndroidJUnit4::class)class FeedDecodeTest {
private val json = Json { ignoreUnknownKeys = true explicitNulls = false coerceInputValues = true }
private val client = XrpcClient( baseUrl = AuthManager.SERVER_URL, http = OkHttpClient.Builder() .connectTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .build(), json = json, )
@Test fun recentFeedDecodesIntoGalleryModels() = runBlocking { val response = client.getFeed(feed = "recent", limit = 20) val galleries = response.items.orEmpty() assertFalse("The recent feed came back empty", galleries.isEmpty())
for (gallery in galleries) { assertTrue("Gallery URI should be an at:// URI", gallery.uri.startsWith("at://")) assertTrue("Creator DID missing", gallery.creator.did.startsWith("did:")) // rkey/shareUrl are derived, so a malformed URI shows up here rather // than as a broken share sheet later. assertTrue(gallery.rkey.isNotEmpty()) assertTrue(gallery.shareUrl.startsWith("https://grain.social/profile/"))
for (photo in gallery.items.orEmpty()) { assertTrue("Photo has no image URL", photo.thumb.isNotEmpty()) assertTrue("Aspect ratio should be positive", photo.aspectRatio.ratio > 0f) // The EXIF view type is where the Swift-to-Kotlin transcription // is densest; touching every computed property exercises it. photo.exif?.let { it.cameraName it.lensName it.settingsLine it.formattedFNumber it.formattedExposureTime it.formattedFocalLength } } } }
@Test fun feedPaginatesWithACursor() = runBlocking { val first = client.getFeed(feed = "recent", limit = 5) val cursor = first.cursor assertNotNull("Recent feed returned no cursor to page with", cursor)
val second = client.getFeed(feed = "recent", limit = 5, cursor = cursor) val firstUris = first.items.orEmpty().map { it.uri }.toSet() val secondUris = second.items.orEmpty().map { it.uri }.toSet() assertFalse("Second page came back empty", secondUris.isEmpty()) assertTrue( "Pages overlap — the cursor isn't being applied", firstUris.intersect(secondUris).isEmpty(), ) }
@Test fun actorProfileDecodesIntoDetailedProfile() = runBlocking { // Resolve a real DID off the feed rather than hardcoding an account // that might be deleted or renamed later. val did = client.getFeed(feed = "recent", limit = 1) .items.orEmpty().first().creator.did
val profile = client.getActorProfile(actor = did) assertTrue(profile.did.startsWith("did:")) assertTrue("Profile handle missing", profile.handle.isNotEmpty()) }
@Test fun actorFeedDecodesForASingleAuthor() = runBlocking { val did = client.getFeed(feed = "recent", limit = 1) .items.orEmpty().first().creator.did
val galleries = client.getFeed(feed = "actor", actor = did).items.orEmpty() assertTrue( "An author's own feed should only contain their galleries", galleries.all { it.creator.did == did }, ) }}