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 }