~ knotless Search/
↑↓ move↵ open⇧↵ all results

grain.social/grain-android

1 collaborator
0
1
main
186 lines · 6.2 KB Raw History
package social.grain.support

import social.grain.data.model.AspectRatio
import social.grain.data.model.AtLabel
import social.grain.data.model.GalleryViewerState
import social.grain.data.model.GrainComment
import social.grain.data.model.GrainGallery
import social.grain.data.model.GrainNotification
import social.grain.data.model.GrainPhoto
import social.grain.data.model.GrainProfile
import social.grain.data.model.GrainProfileDetailed
import social.grain.data.model.GrainStory
import social.grain.data.model.GrainStoryAuthor
import social.grain.data.model.H3Location
import social.grain.util.nowIso
import java.time.Instant

/**
 * Hand-built models for tests that need something to render or reason over.
 *
 * Deliberately not read off the network like the older decode tests: those
 * exist to catch the server changing shape, and these exist to pin behaviour
 * down to one input, which a live feed can't do.
 */
object Fixtures {

    fun instant(minutesAgo: Long = 0): Instant =
        Instant.parse("2026-03-01T12:00:00Z").minusSeconds(minutesAgo * 60)

    fun iso(minutesAgo: Long = 0): String = nowIso(instant(minutesAgo))

    /** Recent enough that anything with a 24-hour window still counts it. */
    fun recentIso(minutesAgo: Long = 5): String =
        nowIso(Instant.now().minusSeconds(minutesAgo * 60))

    fun profile(
        did: String = "did:plc:alice",
        handle: String = "alice.grain.social",
        displayName: String? = "Alice",
        avatar: String? = "https://cdn.grain.test/avatar/alice.jpg",
    ) = GrainProfile(
        cid = "cid-$did",
        did = did,
        handle = handle,
        displayName = displayName,
        avatar = avatar,
        createdAt = iso(60 * 24 * 30),
    )

    fun profileDetailed(
        did: String = "did:plc:alice",
        handle: String = "alice.grain.social",
        displayName: String? = "Alice",
        following: String? = null,
        followedBy: String? = null,
        blocking: String? = null,
        muted: Boolean? = null,
        labels: List<AtLabel>? = null,
    ) = GrainProfileDetailed(
        cid = "cid-$did",
        did = did,
        handle = handle,
        displayName = displayName,
        description = "Photographs of things",
        avatar = "https://cdn.grain.test/avatar/$handle.jpg",
        cameras = listOf("Fujifilm X100V"),
        followersCount = 120,
        followsCount = 80,
        galleryCount = 12,
        createdAt = iso(60 * 24 * 30),
        viewer = social.grain.data.model.ActorViewerState(
            following = following,
            followedBy = followedBy,
            blocking = blocking,
            muted = muted,
        ),
        labels = labels,
    )

    fun photo(
        index: Int = 0,
        width: Int = 3,
        height: Int = 2,
        alt: String? = null,
    ) = GrainPhoto(
        uri = "at://did:plc:alice/social.grain.photo/photo$index",
        cid = "cid-photo$index",
        thumb = "https://cdn.grain.test/thumb/$index.jpg",
        fullsize = "https://cdn.grain.test/full/$index.jpg",
        alt = alt,
        aspectRatio = AspectRatio(width, height),
    )

    fun gallery(
        rkey: String = "gallery1",
        title: String? = "A walk in the fog",
        description: String? = "Six frames from a grey morning",
        creator: GrainProfile = profile(),
        photos: Int = 3,
        favCount: Int? = 12,
        commentCount: Int? = 3,
        labels: List<AtLabel>? = null,
        favUri: String? = null,
        location: H3Location? = null,
    ) = GrainGallery(
        uri = "at://${creator.did}/social.grain.gallery/$rkey",
        cid = "cid-$rkey",
        title = title,
        description = description,
        location = location,
        locationDisplay = location?.name,
        creator = creator,
        items = List(photos) { photo(it) },
        favCount = favCount,
        commentCount = commentCount,
        labels = labels,
        createdAt = iso(30),
        indexedAt = iso(30),
        viewer = GalleryViewerState(fav = favUri),
    )

    fun comment(
        rkey: String = "comment1",
        text: String = "Lovely light",
        author: GrainProfile = profile(),
        replyTo: String? = null,
        favUri: String? = null,
        minutesAgo: Long = 10,
    ) = GrainComment(
        uri = "at://${author.did}/social.grain.comment/$rkey",
        cid = "cid-$rkey",
        author = author,
        text = text,
        replyTo = replyTo,
        createdAt = iso(minutesAgo),
        favCount = 0,
        viewer = social.grain.data.model.CommentViewerState(fav = favUri),
    )

    fun story(
        rkey: String = "story1",
        creator: GrainProfile = profile(),
        createdAt: String = recentIso(),
        expired: Boolean? = null,
        favUri: String? = null,
        labels: List<AtLabel>? = null,
    ) = GrainStory(
        uri = "at://${creator.did}/social.grain.story/$rkey",
        cid = "cid-$rkey",
        creator = creator,
        thumb = "https://cdn.grain.test/story-thumb/$rkey.jpg",
        fullsize = "https://cdn.grain.test/story/$rkey.jpg",
        aspectRatio = AspectRatio(9, 16),
        createdAt = createdAt,
        labels = labels,
        expired = expired,
        viewer = social.grain.data.model.StoryViewerState(fav = favUri),
    )

    fun storyAuthor(
        profile: GrainProfile = profile(),
        storyCount: Int = 2,
        latestAt: String = recentIso(),
    ) = GrainStoryAuthor(profile = profile, storyCount = storyCount, latestAt = latestAt)

    fun notification(
        rkey: String = "notif1",
        reason: String = "gallery-favorite",
        author: GrainProfile = profile(),
        galleryUri: String? = "at://did:plc:alice/social.grain.gallery/gallery1",
        minutesAgo: Long = 5,
        commentText: String? = null,
    ) = GrainNotification(
        uri = "at://${author.did}/notification/$rkey",
        reason = reason,
        createdAt = iso(minutesAgo),
        author = author,
        galleryUri = galleryUri,
        galleryTitle = "A walk in the fog",
        galleryThumb = "https://cdn.grain.test/thumb/0.jpg",
        commentText = commentText,
    )
}

/** Encode a fixture to the JSON the stub server hands back. */
inline fun <reified T> json(value: T): String = testJson.encodeToString(value)