Recently Written · git

ink-update

Ink Update: tells you when Rebind, Ink Recents or Ink Dim has a new version. F-Droid, then Google Play, then GitHub.

git clone https://github.com/equwal/ink-update

Log | Files | Refs


app/src/test/java/dev/equwal/inkupdate/JsonTest.kt (6662 bytes)

1 // SPDX-License-Identifier: GPL-3.0-or-later
2 // Copyright (c) 2026 equwal
3 package dev.equwal.inkupdate
4 
5 import org.junit.Assert.assertEquals
6 import org.junit.Assert.assertNull
7 import org.junit.Assert.assertTrue
8 import org.junit.Test
9 
10 /**
11  * The two answers, as the hosts really send them.
12  *
13  * The F-Droid answers come from https://f-droid.org/api/v1/packages/.
14  * The GitHub answer keeps the shape of
15  * https://api.github.com/repos/equwal/rebind/releases?per_page=10.
16  */
17 class JsonTest {
18 
19     private val page = "https://f-droid.org/packages/org.fdroid.fdroid/"
20 
21     // ---- F-Droid -----------------------------------------------------------
22 
23     /** The real answer for org.fdroid.fdroid. */
24     private val fdroidReal = """
25         {"packageName":"org.fdroid.fdroid","suggestedVersionCode":1023052,
26         "packages":[{"versionName":"2.0-rc1","versionCode":2000041},
27         {"versionName":"2.0-rc0","versionCode":2000040},
28         {"versionName":"2.0-alpha11","versionCode":2000011},
29         {"versionName":"1.23.2","versionCode":1023052}]}
30     """.trimIndent()
31 
32     @Test
33     fun readsARealFdroidAnswer() {
34         val a = Decide.parseFdroid(fdroidReal, page)
35         assertTrue(a is FdroidAnswer.Found)
36         a as FdroidAnswer.Found
37         // The suggested build, not the newest one. F-Droid suggests 1.23.2.
38         assertEquals(1023052L, a.versionCode)
39         assertEquals("1.23.2", a.versionName)
40         assertEquals(page, a.page)
41     }
42 
43     /** All four watched apps get this answer today. It is not a failure. */
44     @Test
45     fun notFoundMeansNotThere() {
46         assertEquals(
47             FdroidAnswer.NotThere,
48             Decide.parseFdroid("""{"error":"NOT_FOUND"}""", page)
49         )
50     }
51 
52     @Test
53     fun aBrokenFdroidAnswerFails() {
54         assertTrue(Decide.parseFdroid("not json", page) is FdroidAnswer.Failed)
55         assertTrue(Decide.parseFdroid("", page) is FdroidAnswer.Failed)
56         assertTrue(Decide.parseFdroid(null, page) is FdroidAnswer.Failed)
57         assertTrue(Decide.parseFdroid("""{"packageName":"a"}""", page) is FdroidAnswer.Failed)
58         assertTrue(Decide.parseFdroid("[1,2,3]", page) is FdroidAnswer.Failed)
59     }
60 
61     // ---- GitHub ------------------------------------------------------------
62 
63     /**
64      * A draft first, then two pre-releases. Every release of these
65      * repositories is a pre-release, so /releases/latest would give nothing.
66      */
67     private val githubReal = """
68         [
69           {"id":1,"tag_name":"v0.0.17-alpha","name":"Rebind 0.0.17-alpha",
70            "draft":true,"prerelease":true,
71            "html_url":"https://github.com/equwal/rebind/releases/tag/untagged-1",
72            "assets":[]},
73           {"id":2,"tag_name":"v0.0.15-alpha","name":"Rebind 0.0.15-alpha",
74            "draft":false,"prerelease":true,
75            "html_url":"https://github.com/equwal/rebind/releases/tag/v0.0.15-alpha",
76            "published_at":"2026-09-20T18:04:11Z",
77            "assets":[
78              {"name":"rebind-0.0.15-alpha-play.aab",
79               "browser_download_url":"https://github.com/equwal/rebind/releases/download/v0.0.15-alpha/rebind-0.0.15-alpha-play.aab"},
80              {"name":"rebind-0.0.15-alpha-play.apk",
81               "browser_download_url":"https://github.com/equwal/rebind/releases/download/v0.0.15-alpha/rebind-0.0.15-alpha-play.apk"},
82              {"name":"rebind-0.0.15-alpha-full.apk",
83               "browser_download_url":"https://github.com/equwal/rebind/releases/download/v0.0.15-alpha/rebind-0.0.15-alpha-full.apk"}
84            ]},
85           {"id":3,"tag_name":"v0.0.14-alpha","draft":false,"prerelease":true,
86            "html_url":"https://github.com/equwal/rebind/releases/tag/v0.0.14-alpha",
87            "assets":[]}
88         ]
89     """.trimIndent()
90 
91     @Test
92     fun skipsTheDraftAndTakesThePreRelease() {
93         val a = Decide.parseGithub(githubReal, "full")
94         assertTrue(a is GithubAnswer.Found)
95         a as GithubAnswer.Found
96         assertEquals("v0.0.15-alpha", a.tag)
97         assertEquals("https://github.com/equwal/rebind/releases/tag/v0.0.15-alpha", a.page)
98         assertEquals(
99             "https://github.com/equwal/rebind/releases/download/" +
100                 "v0.0.15-alpha/rebind-0.0.15-alpha-full.apk",
101             a.apk
102         )
103     }
104 
105     /** Without a wanted word, the first APK wins. The .aab is not an APK. */
106     @Test
107     fun takesTheFirstApkWhenNothingIsPreferred() {
108         val a = Decide.parseGithub(githubReal) as GithubAnswer.Found
109         assertEquals(
110             "https://github.com/equwal/rebind/releases/download/" +
111                 "v0.0.15-alpha/rebind-0.0.15-alpha-play.apk",
112             a.apk
113         )
114     }
115 
116     @Test
117     fun aReleaseWithNoApkGivesNoLink() {
118         val one = """
119             [{"tag_name":"v0.1.0","draft":false,"prerelease":false,
120               "html_url":"https://github.com/equwal/ink-dim/releases/tag/v0.1.0",
121               "assets":[{"name":"notes.txt",
122                 "browser_download_url":"https://example.invalid/notes.txt"}]}]
123         """.trimIndent()
124         val a = Decide.parseGithub(one, "full") as GithubAnswer.Found
125         assertEquals("v0.1.0", a.tag)
126         assertNull(a.apk)
127     }
128 
129     @Test
130     fun anEmptyArrayMeansNoRelease() {
131         assertEquals(GithubAnswer.None, Decide.parseGithub("[]"))
132     }
133 
134     @Test
135     fun onlyDraftsMeanNoRelease() {
136         val drafts = """[{"tag_name":"v9.9.9","draft":true,"assets":[]}]"""
137         assertEquals(GithubAnswer.None, Decide.parseGithub(drafts))
138     }
139 
140     @Test
141     fun aBrokenGithubAnswerFails() {
142         assertTrue(Decide.parseGithub("not json") is GithubAnswer.Failed)
143         assertTrue(Decide.parseGithub("") is GithubAnswer.Failed)
144         assertTrue(Decide.parseGithub(null) is GithubAnswer.Failed)
145         // The rate limit answer is an object, not an array.
146         assertTrue(
147             Decide.parseGithub("""{"message":"API rate limit exceeded"}""")
148                 is GithubAnswer.Failed
149         )
150         assertTrue(Decide.parseGithub("""[{"draft":false}]""") is GithubAnswer.Failed)
151     }
152 
153     // ---- the two together --------------------------------------------------
154 
155     /** What Rebind gets today: not on F-Droid, a newer pre-release on GitHub. */
156     @Test
157     fun rebindToday() {
158         val f = Decide.parseFdroid("""{"error":"NOT_FOUND"}""", page)
159         val g = Decide.parseGithub(githubReal, "full")
160         val r = Decide.source(null, f, g, 14L, "0.0.14-alpha-full")
161         assertTrue(r is Result.Update)
162         r as Result.Update
163         assertEquals(Decide.GITHUB, r.source)
164         assertEquals("0.0.15-alpha", r.versionName)
165         assertTrue(r.apk!!.endsWith("-full.apk"))
166     }
167 }