| 1 |
package io.oxygenhub.android.ui |
| 2 |
|
| 3 |
import io.oxygenhub.android.FakeHubApi |
| 4 |
import io.oxygenhub.android.api.FlowRun |
| 5 |
import io.oxygenhub.android.api.HubException |
| 6 |
import io.oxygenhub.android.api.UserFlowRun |
| 7 |
import io.oxygenhub.android.api.UserSky |
| 8 |
import io.oxygenhub.android.api.IssueBrief |
| 9 |
import io.oxygenhub.android.ui.nav.AccountRoute |
| 10 |
import io.oxygenhub.android.ui.nav.DashboardRoute |
| 11 |
import io.oxygenhub.android.ui.nav.InboxRoute |
| 12 |
import io.oxygenhub.android.ui.nav.IssueRoute |
| 13 |
import io.oxygenhub.android.ui.nav.ProposalRoute |
| 14 |
import io.oxygenhub.android.widget.HealthStrip |
| 15 |
import io.oxygenhub.android.widget.SkyBitmap |
| 16 |
import io.oxygenhub.android.widget.WidgetData |
| 17 |
import io.oxygenhub.android.widget.WidgetTaps |
| 18 |
import io.oxygenhub.android.widget.runnerLine |
| 19 |
import kotlinx.coroutines.test.runTest |
| 20 |
import org.junit.Assert.assertEquals |
| 21 |
import org.junit.Assert.assertFalse |
| 22 |
import org.junit.Assert.assertNotEquals |
| 23 |
import org.junit.Assert.assertNull |
| 24 |
import org.junit.Assert.assertTrue |
| 25 |
import org.junit.Test |
| 26 |
|
| 27 |
class WidgetDataTest { |
| 28 |
@Test |
| 29 |
fun theWidgetShowsTheLatestRunsAndCountsAndAsksForASignInWithoutOne() = runTest { |
| 30 |
val api = FakeHubApi() |
| 31 |
api.userFlowRuns = { (1L..5L).map { UserFlowRun("andy/a", FlowRun(number = it, status = "passed")) } } |
| 32 |
val d = WidgetData.load(api) |
| 33 |
assertEquals(listOf(1L, 2L, 3L), d.runs.map { it.run.number }) |
| 34 |
assertEquals(1, d.reviews) |
| 35 |
assertFalse(WidgetData.load(null).signedIn) |
| 36 |
} |
| 37 |
|
| 38 |
@Test |
| 39 |
fun aPartTheHubCannotGiveIsLeftOutNotTheWholeWidget() = runTest { |
| 40 |
val api = FakeHubApi() |
| 41 |
api.userFlowRuns = { throw HubException.Http(404, "no such API route") } |
| 42 |
val d = WidgetData.load(api) |
| 43 |
assertEquals(emptyList<UserFlowRun>(), d.runs) |
| 44 |
assertEquals(1, d.reviews) |
| 45 |
api.userProposals = { throw HubException.Http(500, "down") } |
| 46 |
assertNull(WidgetData.load(api).reviews) |
| 47 |
} |
| 48 |
|
| 49 |
@Test |
| 50 |
fun theWidgetFetchesYourSkyAndALostSkyLeavesThePlainSurface() = runTest { |
| 51 |
val api = FakeHubApi() |
| 52 |
val sky = UserSky(now = 10 * 86_400_000L, repos = listOf("andy/a"), events = listOf(listOf(0L, 0L, 9 * 86_400_000L, 3L))) |
| 53 |
api.userSky = { sky } |
| 54 |
assertEquals(sky, WidgetData.load(api).sky) |
| 55 |
api.userSky = { throw HubException.Http(404, "no such API route") } |
| 56 |
val d = WidgetData.load(api) |
| 57 |
assertNull(d.sky) |
| 58 |
assertEquals(1, d.reviews) |
| 59 |
} |
| 60 |
|
| 61 |
@Test |
| 62 |
fun onlyRealActivityIsDrawn() { |
| 63 |
assertFalse("nothing fetched", SkyBitmap.drawable(null)) |
| 64 |
assertFalse("no repositories", SkyBitmap.drawable(UserSky())) |
| 65 |
assertFalse("repositories but no events", SkyBitmap.drawable(UserSky(repos = listOf("andy/a")))) |
| 66 |
assertFalse("only malformed events", SkyBitmap.drawable(UserSky(repos = listOf("andy/a"), events = listOf(listOf(7L, 0L, 0L, 1L))))) |
| 67 |
assertTrue(SkyBitmap.drawable(UserSky(now = 1, repos = listOf("andy/a"), events = listOf(listOf(0L, 4L, 0L, 1L))))) |
| 68 |
} |
| 69 |
|
| 70 |
@Test |
| 71 |
fun theSkysColoursFollowTheTheme() { |
| 72 |
val (light, dark) = SkyBitmap.colours(false) to SkyBitmap.colours(true) |
| 73 |
assertEquals(24, light.size) |
| 74 |
assertEquals(24, dark.size) |
| 75 |
assertNotEquals(light, dark) |
| 76 |
assertTrue("every channel is a fraction", (light + dark).all { it in 0f..1f }) |
| 77 |
} |
| 78 |
|
| 79 |
@Test |
| 80 |
fun theCountsRowSaysWhatIsAssignedAndOneOfAKindOpensItself() = runTest { |
| 81 |
val api = FakeHubApi() |
| 82 |
val d = WidgetData.load(api) |
| 83 |
assertEquals(1, d.assigned) |
| 84 |
assertEquals(359L, d.onlyAssigned?.number) |
| 85 |
assertEquals(300L, d.onlyReview?.number) |
| 86 |
api.userIssues = { listOf(IssueBrief("andy/a", 1), IssueBrief("andy/a", 2)) } |
| 87 |
val two = WidgetData.load(api) |
| 88 |
assertEquals(2, two.assigned) |
| 89 |
assertNull("two open the dashboard, not one of them", two.onlyAssigned) |
| 90 |
api.userIssues = { throw HubException.Http(404, "no such API route") } |
| 91 |
val old = WidgetData.load(api) |
| 92 |
assertNull("a hub before /user/issues: the count is left out", old.assigned) |
| 93 |
assertEquals(1, old.reviews) |
| 94 |
} |
| 95 |
|
| 96 |
@Test |
| 97 |
fun theRunnerShowsOnlyWhileThePhoneServes() = runTest { |
| 98 |
val api = FakeHubApi() |
| 99 |
assertNull(WidgetData.load(api).runnerJobs) |
| 100 |
assertEquals(listOf("andy/a #7 test"), WidgetData.load(api, listOf("andy/a #7 test")).runnerJobs) |
| 101 |
assertEquals("Waiting for jobs", runnerLine(emptyList())) |
| 102 |
assertEquals("andy/a #7 test", runnerLine(listOf("andy/a #7 test"))) |
| 103 |
assertEquals("2 jobs", runnerLine(listOf("andy/a #7 test", "andy/b #2 build"))) |
| 104 |
} |
| 105 |
|
| 106 |
@Test |
| 107 |
fun aTapOnACountOpensItsScreen() { |
| 108 |
assertEquals(InboxRoute, WidgetTaps.route("inbox", "", 0)) |
| 109 |
assertEquals(DashboardRoute, WidgetTaps.route("dashboard", "", 0)) |
| 110 |
assertEquals(AccountRoute, WidgetTaps.route("account", "", 0)) |
| 111 |
assertEquals(ProposalRoute("andy", "a", 3), WidgetTaps.route("proposal", "andy/a", 3)) |
| 112 |
assertEquals(IssueRoute("andy", "a", 4), WidgetTaps.route("issue", "andy/a", 4)) |
| 113 |
assertEquals("a broken reference falls back to the dashboard", DashboardRoute, WidgetTaps.route("issue", "nonsense", 4)) |
| 114 |
assertNull("not from the widget", WidgetTaps.route(null, null, 0)) |
| 115 |
} |
| 116 |
|
| 117 |
@Test |
| 118 |
fun needsYouAndTheHealthStripComeFromWhatTheWidgetFetches() = runTest { |
| 119 |
val api = FakeHubApi() |
| 120 |
val statuses = listOf("running", "passed", "failed", "cancelled", "passed", "passed") |
| 121 |
api.userFlowRuns = { statuses.mapIndexed { i, st -> UserFlowRun("andy/a", FlowRun(number = 10L - i, status = st)) } } |
| 122 |
val d = WidgetData.load(api) |
| 123 |
assertEquals(300L, d.topReview?.number) |
| 124 |
assertEquals(359L, d.topAssigned?.number) |
| 125 |
assertEquals("all the runs fetched, not just the three shown", statuses, d.health) |
| 126 |
assertEquals(3, d.runs.size) |
| 127 |
} |
| 128 |
|
| 129 |
@Test |
| 130 |
fun theHealthSummaryCountsFinishedRunsOnly() { |
| 131 |
assertEquals("75% of the last 4 finished runs passed", HealthStrip.summary(listOf("running", "passed", "failed", "cancelled", "passed", "passed"))) |
| 132 |
assertEquals("100% of the last finished run passed", HealthStrip.summary(listOf("passed", "queued"))) |
| 133 |
assertNull("nothing finished", HealthStrip.summary(listOf("running", "cancelled"))) |
| 134 |
assertNull(HealthStrip.summary(emptyList())) |
| 135 |
assertEquals(HealthStrip.Kind.Failed, HealthStrip.kind("error")) |
| 136 |
} |
| 137 |
} |