OXYGENHUB
# 29a375612f92 oxygenhub-android / app / src / test / java / io / oxygenhub / android / ui / DashboardViewModelTest.kt
6.2 KiB · last changed The Dashboard refreshes each time it comes back to the front (closes #35) 2 days ago source blame history raw
1
package io.oxygenhub.android.ui
2
3
import io.oxygenhub.android.FakeHubApi
4
import io.oxygenhub.android.Fixtures
5
import io.oxygenhub.android.MainDispatcherRule
6
import io.oxygenhub.android.api.Avatar
7
import io.oxygenhub.android.api.HubException
8
import io.oxygenhub.android.api.UserSky
9
import io.oxygenhub.android.auth.Session
10
import io.oxygenhub.android.ui.backdrop.Frame
11
import io.oxygenhub.android.ui.backdrop.repoSkyOrNull
12
import io.oxygenhub.android.ui.backdrop.skyEvents
13
import io.oxygenhub.android.ui.backdrop.straight
14
import io.oxygenhub.android.ui.common.Load
15
import io.oxygenhub.android.ui.dashboard.Dashboard
16
import io.oxygenhub.android.ui.dashboard.DashboardViewModel
17
import org.junit.Assert.assertEquals
18
import org.junit.Assert.assertFalse
19
import org.junit.Assert.assertNull
20
import org.junit.Assert.assertTrue
21
import org.junit.Rule
22
import org.junit.Test
23
24
class DashboardViewModelTest {
25
    @get:Rule val main = MainDispatcherRule()
26
27
    private val api = FakeHubApi()
28
    private val session = Session("https://oxygenhub.io", "andymccall", "t")
29
30
    private fun ready(vm: DashboardViewModel): Dashboard = (vm.state.value as Load.Ready).value
31
32
    @Test
33
    fun greetsAndListsTheUsersRecentRepositories() {
34
        val d = ready(DashboardViewModel(api, session) { 9 })
35
        assertEquals("Good morning, Andy McCall", d.greeting)
36
        assertTrue(d.recentAreYours)
37
        assertEquals(listOf("andymccall/oxygenflow", "andymccall/secret-plans"), d.recent.map { it.slug })
38
        assertEquals(2, d.repositoryCount)
39
    }
40
41
    @Test
42
    fun showsTheAccountsAvatarAndKeepsItWhenTheHubFails() {
43
        val mine = Avatar.Identicon(196, setOf(3 to 3))
44
        api.avatar = { if (it == "andymccall") mine else null }
45
        val vm = DashboardViewModel(api, session) { 9 }
46
        assertEquals(mine, ready(vm).avatar)
47
        assertEquals("andymccall", ready(vm).username)
48
        // A failed fetch keeps the one before; the page still loads.
49
        api.avatar = { throw HubException.Http(500, "down") }
50
        vm.refresh()
51
        assertEquals(mine, ready(vm).avatar)
52
    }
53
54
    @Test
55
    fun fetchesAfreshWhenItComesBackToTheFront() {
56
        val vm = DashboardViewModel(api, session) { 9 }
57
        val before = api.calls.count { it == "repos" }
58
        // Back from landing a proposal (#35): the dashboard asks the hub again.
59
        vm.resumed()
60
        assertEquals(before + 1, api.calls.count { it == "repos" })
61
        assertEquals(2, ready(vm).repositoryCount)
62
    }
63
64
    @Test
65
    fun drawsYourSkyFromTheHubAndTheFieldWithoutIt() {
66
        val vm = DashboardViewModel(api, session) { 9 }
67
        val sky = ready(vm).sky!!
68
        val events = skyEvents(sky)
69
        assertEquals(1, events.size)
70
        assertEquals(1f, events[0].ageDays, 0.001f)
71
        assertEquals(3u, events[0].n)
72
        // A hub before /user/sky: the dashboard loads, with no sky.
73
        api.userSky = { throw HubException.Http(404, "no such endpoint") }
74
        vm.refresh()
75
        assertNull(ready(vm).sky)
76
        assertEquals(2, ready(vm).repositoryCount)
77
    }
78
79
    @Test
80
    fun aRepositorysSkyIsNothingFromAHubWithoutIt() = kotlinx.coroutines.test.runTest {
81
        assertEquals(listOf("andymccall/oxygen"), repoSkyOrNull(api, "andymccall", "oxygen")?.repos)
82
        api.userSky = { throw HubException.Http(404, "no such endpoint") }
83
        assertNull(repoSkyOrNull(api, "andymccall", "oxygen"))
84
    }
85
86
    @Test
87
    fun leavesOutMalformedSkyEvents() {
88
        val sky = UserSky(now = 0, repos = listOf("a/b"), events = listOf(listOf(0L, 9L, 0L, 1L), listOf(3L, 0L, 0L, 1L), listOf(0L), listOf(0L, 4L, 5L, 0L)))
89
        val events = skyEvents(sky)
90
        assertEquals(1, events.size)
91
        assertEquals(4u, events[0].kind)
92
        assertEquals(0f, events[0].ageDays)
93
        assertEquals("at least one mark", 1u, events[0].n)
94
    }
95
96
    @Test
97
    fun decodesAFrameAndUnpremultipliesItsColours() {
98
        val bytes = java.nio.ByteBuffer.allocate(8).order(java.nio.ByteOrder.LITTLE_ENDIAN).putFloat(1.5f).putFloat(-2f).array()
99
        assertTrue(Frame.floats(bytes).contentEquals(floatArrayOf(1.5f, -2f)))
100
        val c = straight(0.25f, 0f, 0.5f, 0.5f)
101
        assertEquals(0.5f, c.red, 0.01f)
102
        assertEquals(1f, c.blue, 0.01f)
103
        assertEquals(0.5f, c.alpha, 0.01f)
104
        assertEquals(0f, straight(0.1f, 0.1f, 0.1f, 0f).alpha)
105
    }
106
107
    @Test
108
    fun showsProposalsToReviewAndNoneFromAHubWithoutTheCall() {
109
        val vm = DashboardViewModel(api, session) { 9 }
110
        assertEquals(listOf(300L), ready(vm).proposals?.review?.map { it.number })
111
        assertEquals("andymccall" to "oxygenhub", ready(vm).proposals!!.review[0].let { it.owner to it.name })
112
        api.userProposals = { throw HubException.Http(404, "no such endpoint") }
113
        vm.refresh()
114
        assertNull(ready(vm).proposals)
115
        assertEquals(2, ready(vm).repositoryCount)
116
    }
117
118
    @Test
119
    fun withNoRepositoriesOfTheirOwnShowsTheHubs() {
120
        val d = ready(DashboardViewModel(api, session.copy(username = "newcomer")) { 14 }.also {
121
            api.user = { Fixtures.user.copy(username = "newcomer", displayName = "") }
122
            it.refresh()
123
        })
124
        assertEquals("Good afternoon, newcomer", d.greeting)
125
        assertFalse(d.recentAreYours)
126
        assertEquals("doomsdayone/tetris", d.recent.first().slug)
127
    }
128
129
    @Test
130
    fun withoutUserReadGreetsByTheSessionsName() {
131
        api.user = { throw HubException.Http(403, "this token lacks the user:read scope") }
132
        val d = ready(DashboardViewModel(api, session) { 22 })
133
        assertEquals("Good evening, andymccall", d.greeting)
134
        assertNull(d.user)
135
    }
136
137
    @Test
138
    fun aFailureAndARetry() {
139
        api.repositories = { throw HubException.Http(503, "down") }
140
        val vm = DashboardViewModel(api, session) { 9 }
141
        assertTrue(vm.state.value is Load.Failed)
142
        api.repositories = { Fixtures.repos }
143
        vm.refresh()
144
        assertTrue(vm.state.value is Load.Ready)
145
    }
146
147
    @Test
148
    fun greetings() {
149
        assertEquals("Good evening, a", DashboardViewModel.greeting(4, "a"))
150
        assertEquals("Good morning, a", DashboardViewModel.greeting(5, "a"))
151
        assertEquals("Good afternoon, a", DashboardViewModel.greeting(12, "a"))
152
        assertEquals("Good evening, a", DashboardViewModel.greeting(18, "a"))
153
    }
154
}