Recently Written · git

subrep-android

Subrep on Android: live captions of the sound of the phone, made on the phone by Whisper, shared by link.

git clone https://github.com/equwal/subrep-android

Log | Files | Refs


app/src/test/kotlin/com/honjimaku/subrep/ProtocolTest.kt (4719 bytes)

1 package com.honjimaku.subrep
2 
3 import io.kotest.property.Arb
4 import io.kotest.property.arbitrary.element
5 import io.kotest.property.arbitrary.int
6 import io.kotest.property.arbitrary.list
7 import io.kotest.property.arbitrary.string
8 import io.kotest.property.checkAll
9 import kotlinx.coroutines.runBlocking
10 import org.json.JSONObject
11 import org.junit.Assert.assertEquals
12 import org.junit.Assert.assertNull
13 import org.junit.Assert.assertTrue
14 import org.junit.Test
15 
16 class RoomTest {
17 
18     /** What the relay accepts as a room id. */
19     private val roomId = Regex("^[a-zA-Z0-9_-]{6,64}$")
20 
21     @Test
22     fun aRoomIdIsOneTheRelayAcceptsAndTwoAreNotTheSame() {
23         val ids = List(200) { Room.newId() }
24         ids.forEach { assertTrue(it, roomId.matches(it)) }
25         ids.forEach { assertEquals(12, it.length) }
26         assertEquals(200, ids.toSet().size)
27     }
28 
29     @Test
30     fun aSecretIsLongEnoughForTheRelay() {
31         repeat(50) { assertTrue(Room.newSecret().length >= 16) }
32     }
33 
34     @Test
35     fun theWatchLinkIsTheHttpsPageOfTheRoom() {
36         assertEquals("https://honjimaku.com/subrep/w/abc123def456", Room.watchUrl("wss://honjimaku.com/subrep", "abc123def456"))
37         assertEquals("https://honjimaku.com/subrep/w/abc123def456", Room.watchUrl("wss://honjimaku.com/subrep/", "abc123def456"))
38         assertEquals("http://127.0.0.1:8812/w/r", Room.watchUrl("ws://127.0.0.1:8812", "r"))
39     }
40 }
41 
42 class MessagesTest {
43 
44     private val texts = Arb.string(0..60)
45     private val types = Arb.element("partial", "final", "clear")
46 
47     /** A caption reaches the viewer page as the desktop app sends it: type, text, tr, ts. */
48     @Test
49     fun aCaptionHasWhatTheViewerPageReads(): Unit = runBlocking {
50         checkAll(types, texts) { type, text ->
51             val json = JSONObject(Messages.caption(Caption(type, text), nowSeconds = 12.5))
52             assertEquals(type, json.getString("type"))
53             assertEquals(text, json.getString("text"))
54             assertEquals("", json.getString("tr"))
55             assertEquals(12.5, json.getDouble("ts"), 0.0)
56         }
57     }
58 
59     @Test
60     fun anErrorGivesItsReason() {
61         assertEquals("wrong room secret", Messages.error("""{"type":"error","error":"wrong room secret"}"""))
62         assertEquals("error", Messages.error("""{"type":"error"}"""))
63         assertNull(Messages.error("""{"type":"ready","room":"x"}"""))
64         assertNull(Messages.error("junk"))
65     }
66 
67     @Test
68     fun theHelloAndTheStatusHaveWhatTheRelayReads(): Unit = runBlocking {
69         checkAll(texts, texts, texts) { secret, lang, title ->
70             val hello = JSONObject(Messages.relayHello(secret, lang, title))
71             assertEquals(secret, hello.getString("secret"))
72             assertEquals(lang, hello.getString("lang"))
73             assertEquals(title, hello.getString("title"))
74             val status = JSONObject(Messages.status(true, lang, title))
75             assertEquals("status", status.getString("type"))
76             assertTrue(status.getBoolean("live"))
77             assertEquals(lang, status.getString("lang"))
78         }
79         assertTrue(Messages.isReady("""{"type":"ready","room":"x"}"""))
80     }
81 }
82 
83 class PcmTest {
84 
85     private fun bytesOf(samples: List<Int>): ByteArray {
86         val bytes = ByteArray(samples.size * 2)
87         samples.forEachIndexed { i, s ->
88             bytes[2 * i] = (s and 0xFF).toByte()
89             bytes[2 * i + 1] = ((s shr 8) and 0xFF).toByte()
90         }
91         return bytes
92     }
93 
94     /** The peak of a frame is the largest sample size in it, with the sign taken away. */
95     @Test
96     fun thePeakIsTheLargestSampleSize(): Unit = runBlocking {
97         checkAll(Arb.list(Arb.int(-32768..32767), 0..400)) { samples ->
98             val bytes = bytesOf(samples)
99             val expected = samples.maxOfOrNull { if (it < 0) -it else it } ?: 0
100             assertEquals(expected, Pcm.peak(bytes, bytes.size))
101         }
102     }
103 
104     /** Each sample comes out as its value over 32768, in the same order. */
105     @Test
106     fun theFloatsAreTheSamplesOver32768(): Unit = runBlocking {
107         checkAll(Arb.list(Arb.int(-32768..32767), 0..400)) { samples ->
108             val bytes = bytesOf(samples)
109             val out = FloatArray(samples.size)
110             assertEquals(samples.size, Pcm.toFloat(bytes, bytes.size, out))
111             samples.forEachIndexed { i, s -> assertEquals(s / 32768f, out[i], 0f) }
112         }
113     }
114 
115     @Test
116     fun onlyTheFirstCountBytesCount() {
117         val bytes = byteArrayOf(0, 0, 0, 0x7F.toByte())
118         assertEquals(0, Pcm.peak(bytes, 2))
119         assertEquals(32512, Pcm.peak(bytes, 4))
120         assertEquals(0, Pcm.peak(bytes, 3))
121         val out = FloatArray(4)
122         assertEquals(1, Pcm.toFloat(bytes, 3, out))
123     }
124 }