OXYGENHUB
# 6fcaca2bd500 oxygenhub-android / app / src / test / java / io / oxygenhub / android / FakeHubApi.kt
10.0 KiB · last changed Releases and search on the phone (refs #3) 10 days ago source blame history raw
5ae4af48 Andy McCall ↶ 1
package io.oxygenhub.android
2
db00632a Andy McCall ↶ 3
import io.oxygenhub.android.api.Avatar
e2df27a8 Andy McCall ↶ 4
import io.oxygenhub.android.api.Check
5
import io.oxygenhub.android.api.Proposal
6
import io.oxygenhub.android.api.ProposalState
5ae4af48 Andy McCall ↶ 7
import io.oxygenhub.android.api.HubApi
8
import io.oxygenhub.android.api.Inbox
9
import io.oxygenhub.android.api.Issue
10
import io.oxygenhub.android.api.IssueState
11
import io.oxygenhub.android.api.Repository
12
import io.oxygenhub.android.api.User
13
14
/** A hub in memory: answers from the fixtures, or the failure set for a call. */
15
class FakeHubApi : HubApi {
16
    var user: () -> User = { Fixtures.user }
17
    var repositories: () -> List<Repository> = { Fixtures.repos }
18
    var issues: (IssueState) -> List<Issue> = { state ->
19
        Fixtures.issues.filter { state == IssueState.All || it.state == state.query }
20
    }
21
    var inbox: () -> Inbox = { Fixtures.inbox }
22
    var markRead: (Long) -> Unit = {}
23
    var markAllRead: () -> Unit = {}
24
    var revoke: () -> Unit = {}
db00632a Andy McCall ↶ 25
    var avatar: (String) -> Avatar? = { null }
e2df27a8 Andy McCall ↶ 26
    var proposals: (ProposalState) -> List<Proposal> = { state ->
27
        Fixtures.proposals.filter {
28
            when (state) {
29
                ProposalState.Open -> it.isOpen
30
                ProposalState.All -> true
31
                else -> it.state == state.query
32
            }
33
        }
34
    }
35
    var proposal: (Long) -> Proposal = { n -> Fixtures.proposals.first { it.number == n } }
36
    var checks: (Long) -> List<Check> = { Fixtures.checks }
37
    var land: (Long) -> Proposal = { n -> proposal(n).copy(state = "landed", landed = io.oxygenhub.android.api.Landed("andymccall", "api (token phone)", 1)) }
d1f635be Andy McCall ↶ 38
    var userProposals: () -> io.oxygenhub.android.api.UserProposals = {
39
        io.oxygenhub.android.api.UserProposals(
40
            review = listOf(io.oxygenhub.android.api.ProposalBrief("andymccall/oxygenhub", 300, "Show a column's archived cards", "ada")),
41
        )
42
    }
e2df27a8 Andy McCall ↶ 43
    var autoLand: (Long, Boolean) -> Proposal = { n, on -> proposal(n).copy(autoLand = if (on) "andymccall" else null) }
5ae4af48 Andy McCall ↶ 44
45
    val calls = mutableListOf<String>()
46
47
    override suspend fun user(): User = user.invoke().also { calls += "user" }
48
    override suspend fun repositories(): List<Repository> = repositories.invoke().also { calls += "repos" }
49
    override suspend fun issues(owner: String, name: String, state: IssueState): List<Issue> =
50
        issues.invoke(state).also { calls += "issues $owner/$name ${state.query}" }
51
    override suspend fun inbox(limit: Int): Inbox = inbox.invoke().also { calls += "inbox" }
52
    override suspend fun markRead(id: Long) {
53
        calls += "read $id"
54
        markRead.invoke(id)
55
    }
56
    override suspend fun markAllRead() {
57
        calls += "read all"
58
        markAllRead.invoke()
e2df27a8 Andy McCall ↶ 59
    }
4aee5293 Andy McCall ↶ 60
    var runnerToken: () -> io.oxygenhub.android.api.RunnerToken = { io.oxygenhub.android.api.RunnerToken("flowreg_test", "andymccall") }
61
    override suspend fun runnerToken() = runnerToken.invoke().also { calls += "runner token" }
dfbc3e97 Andy McCall ↶ 62
    var releaseList: List<io.oxygenhub.android.api.Release> = emptyList()
63
    override suspend fun releases(owner: String, name: String) = releaseList.also { calls += "releases" }
64
    var hits: (String) -> List<io.oxygenhub.android.api.SearchHit> = { emptyList() }
65
    override suspend fun search(query: String) = hits(query).also { calls += "search $query" }
1c42a70f Andy McCall ↶ 66
    var runList: List<io.oxygenhub.android.api.FlowRun> = emptyList()
67
    override suspend fun runs(owner: String, name: String) = runList.also { calls += "runs" }
68
    val runStore = mutableMapOf<Long, io.oxygenhub.android.api.FlowRun>()
69
    override suspend fun run(owner: String, name: String, number: Long) = runStore.getValue(number).also { calls += "run $number" }
70
    val logs = mutableMapOf<String, MutableList<io.oxygenhub.android.api.LogLine>>()
71
    override suspend fun jobLog(owner: String, name: String, number: Long, job: String, after: Long) =
72
        logs[job].orEmpty().filter { it.seq > after }.also { calls += "log $job after $after" }
73
    override suspend fun rerunRun(owner: String, name: String, number: Long) {
74
        calls += "rerun $number"
75
    }
76
    override suspend fun rerunJob(owner: String, name: String, number: Long, job: String) {
77
        calls += "rerun $number $job"
78
    }
79
    override suspend fun cancelRun(owner: String, name: String, number: Long) {
80
        calls += "cancel $number"
81
        runStore[number]?.let { runStore[number] = it.copy(status = "cancelled") }
82
    }
e833eb0a Andy McCall ↶ 83
    var projectsOf: (String) -> List<io.oxygenhub.android.api.Project> = { emptyList() }
84
    override suspend fun projects(owner: String) = projectsOf(owner).also { calls += "projects $owner" }
85
    var boards = mutableMapOf<Long, io.oxygenhub.android.api.Board>()
86
    override suspend fun board(owner: String, number: Long) = boards.getValue(number).also { calls += "board $owner/$number" }
87
    override suspend fun moveCard(owner: String, number: Long, card: Long, column: String) {
88
        calls += "move $card $column"
89
        val b = boards.getValue(number)
90
        val moving = b.columns.flatMap { it.cards }.first { it.id == card }
91
        boards[number] = b.copy(columns = b.columns.map { c ->
92
            val rest = c.cards.filter { it.id != card }
93
            if (c.name == column) c.copy(cards = rest + moving) else c.copy(cards = rest)
94
        })
95
    }
31e4f375 Andy McCall ↶ 96
    val issueStore = mutableMapOf<Long, io.oxygenhub.android.api.Issue>()
97
    val commentStore = mutableMapOf<Long, MutableList<io.oxygenhub.android.api.Comment>>()
98
    var repoLabels = listOf(io.oxygenhub.android.api.Label("bug", "#c62d47"), io.oxygenhub.android.api.Label("ui", "#0969da"))
99
    override suspend fun issue(owner: String, name: String, number: Long) =
100
        (issueStore[number] ?: throw io.oxygenhub.android.api.HubException.Http(404, "no such issue")).also { calls += "issue $number" }
101
    override suspend fun issueComments(owner: String, name: String, number: Long) = commentStore[number].orEmpty().toList()
102
    override suspend fun comment(owner: String, name: String, number: Long, body: String): io.oxygenhub.android.api.Comment {
103
        calls += "comment $number"
104
        val c = io.oxygenhub.android.api.Comment(id = (commentStore.values.sumOf { it.size } + 1).toLong(), author = "andymccall", body = body)
105
        commentStore.getOrPut(number) { mutableListOf() } += c
106
        issueStore[number]?.let { issueStore[number] = it.copy(comments = it.comments + 1) }
107
        return c
108
    }
109
    override suspend fun setIssueState(owner: String, name: String, number: Long, open: Boolean, reason: String): io.oxygenhub.android.api.Issue {
110
        calls += "state $number ${if (open) "open" else "closed:$reason"}"
111
        val i = issueStore.getValue(number).copy(state = if (open) "open" else "closed", reason = if (open) "" else reason)
112
        issueStore[number] = i
113
        return i
114
    }
115
    override suspend fun createIssue(owner: String, name: String, title: String, body: String): io.oxygenhub.android.api.Issue {
116
        val n = (issueStore.keys.maxOrNull() ?: 0) + 1
117
        val i = io.oxygenhub.android.api.Issue(n, title, body, author = "andymccall")
118
        issueStore[n] = i
119
        calls += "create $title"
120
        return i
121
    }
122
    override suspend fun labels(owner: String, name: String) = repoLabels
123
    override suspend fun setIssueLabels(owner: String, name: String, number: Long, labels: List<String>): io.oxygenhub.android.api.Issue {
124
        val i = issueStore.getValue(number).copy(labels = repoLabels.filter { it.name in labels })
125
        issueStore[number] = i
126
        return i
127
    }
98dbd122 Andy McCall ↶ 128
    var repository: io.oxygenhub.android.api.Repository = io.oxygenhub.android.api.Repository("andymccall", "demo", defaultBookmark = "main")
129
    override suspend fun repository(owner: String, name: String) = repository.also { calls += "repository" }
130
    var tree: (String, String) -> List<io.oxygenhub.android.api.TreeEntry> = { _, _ -> emptyList() }
131
    override suspend fun tree(owner: String, name: String, ref: String, path: String) =
132
        tree.invoke(ref, path).also { calls += "tree $ref:$path" }
133
    var files: Map<String, String> = emptyMap()
134
    override suspend fun file(owner: String, name: String, ref: String, path: String): String {
135
        calls += "file $ref:$path"
136
        return files[path] ?: throw io.oxygenhub.android.api.HubException.Http(404, "no such file")
137
    }
138
    var history: io.oxygenhub.android.api.History = io.oxygenhub.android.api.History()
139
    override suspend fun history(owner: String, name: String, ref: String, path: String?, offset: Int, limit: Int) =
140
        history.also { calls += "history $ref:${path.orEmpty()}" }
141
    var change: (String) -> io.oxygenhub.android.api.ChangeDetail = { error("no change") }
142
    override suspend fun change(owner: String, name: String, hash: String) = change.invoke(hash).also { calls += "change $hash" }
143
    var refs: Pair<List<String>, List<String>> = listOf("main") to emptyList()
144
    override suspend fun refs(owner: String, name: String) = refs.also { calls += "refs" }
ff65ea45 Andy McCall ↶ 145
    override suspend fun userProposals(landable: Boolean) =
146
        userProposals.invoke().also { calls += if (landable) "user proposals, landable" else "user proposals" }
e2df27a8 Andy McCall ↶ 147
    override suspend fun proposals(owner: String, name: String, state: ProposalState): List<Proposal> =
148
        proposals.invoke(state).also { calls += "proposals $owner/$name ${state.query}" }
149
    override suspend fun proposal(owner: String, name: String, number: Long): Proposal =
150
        proposal.invoke(number).also { calls += "proposal $number" }
151
    override suspend fun checks(owner: String, name: String, number: Long): List<Check> =
152
        checks.invoke(number).also { calls += "checks $number" }
153
    override suspend fun land(owner: String, name: String, number: Long): Proposal {
154
        calls += "land $number"
155
        return land.invoke(number)
156
    }
157
    override suspend fun setAutoLand(owner: String, name: String, number: Long, on: Boolean): Proposal {
158
        calls += "auto-land $number $on"
159
        return autoLand.invoke(number, on)
5ae4af48 Andy McCall ↶ 160
    }
db00632a Andy McCall ↶ 161
    override suspend fun avatar(name: String): Avatar? = avatar.invoke(name).also { calls += "avatar $name" }
5ae4af48 Andy McCall ↶ 162
    override suspend fun revokeToken() {
163
        calls += "revoke"
164
        revoke.invoke()
165
    }
166
}