Reproduce malformed feedback event handling in the UI
This commit is contained in:
1 parent
a1ce486e89
commit
317f362a7a
3 files changed
+107
-14
No files matched your search
@@ -0,0 +1,73 @@
|
||||
package com.utun.chat.data
|
||||
|
||||
import java.nio.ByteBuffer
|
||||
import java.nio.ByteOrder
|
||||
import java.nio.charset.CharacterCodingException
|
||||
import org.junit.Assert.*
|
||||
import org.junit.Test
|
||||
|
||||
/** Настоящий wire-разбор, используемый ViewModel; формат фиксируют chat_event.h и C-производители событий. */
|
||||
class FeedbackEventTest {
|
||||
private fun changed(channel: String = "123", kind: Int = 1): ByteArray {
|
||||
val text = channel.toByteArray(Charsets.UTF_8)
|
||||
return byteArrayOf(text.size.toByte()) + text + ByteArray(32) { it.toByte() } + byteArrayOf(kind.toByte())
|
||||
}
|
||||
private fun result(id: Long = 7, flag: Int = 1, text: ByteArray = "{}".toByteArray()): ByteArray =
|
||||
ByteBuffer.allocate(9 + text.size).order(ByteOrder.LITTLE_ENDIAN).putLong(id).put(flag.toByte()).put(text).array()
|
||||
|
||||
@Test fun changedEventKeepsCanonicalChannelMessageAndFeedbackKind() {
|
||||
val event = requireNotNull(parseFeedbackChangedEvent(changed("9223372036854775807", 2)))
|
||||
assertEquals("9223372036854775807", event.channelId); assertEquals(2, event.kind)
|
||||
assertEquals("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", event.messageId)
|
||||
}
|
||||
|
||||
@Test fun truncatedChangedEventsFailInsteadOfBeingSilentlyIgnored() {
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(null) }
|
||||
for (size in 0..34) assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(ByteArray(size)) }
|
||||
val valid = changed()
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(valid.copyOf(valid.size - 1)) }
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(valid + byteArrayOf(0)) }
|
||||
}
|
||||
|
||||
@Test fun invalidChannelAndUnknownKindCannotTriggerASnapshotRequest() {
|
||||
for (channel in listOf("", "0", "01", "-1", "+1", "1a", "é", "9223372036854775808", "1".repeat(20))) {
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(changed(channel)) }
|
||||
}
|
||||
for (kind in listOf(0, 3, 255)) {
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackChangedEvent(changed(kind = kind)) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun resultPreservesAllRequestBitsAndUnicodeErrorText() {
|
||||
val id = 0xfedcba9876543210uL.toLong()
|
||||
val event = requireNotNull(parseFeedbackResultEvent(result(id, 0, "{\"error\":\"Отказ 😀\"}".toByteArray())))
|
||||
assertEquals(id, event.requestId); assertFalse(event.success); assertEquals("Отказ 😀", event.json.getString("error"))
|
||||
val background = requireNotNull(parseFeedbackResultEvent(result(0)))
|
||||
assertEquals(0L, background.requestId); assertTrue(background.success)
|
||||
}
|
||||
|
||||
@Test fun truncatedResultAndEmptyJsonFailForTheCallerToReport() {
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackResultEvent(null) }
|
||||
for (size in 0..9) assertThrows(IllegalArgumentException::class.java) { parseFeedbackResultEvent(ByteArray(size)) }
|
||||
}
|
||||
|
||||
@Test fun successFlagMustBeExactlyZeroOrOne() {
|
||||
for (flag in listOf(2, 127, 255)) {
|
||||
assertThrows(IllegalArgumentException::class.java) { parseFeedbackResultEvent(result(flag = flag)) }
|
||||
}
|
||||
}
|
||||
|
||||
@Test fun invalidUtf8AndMalformedJsonAreNotReplacedByAValidSnapshot() {
|
||||
val corrupt = "{\"text\":\"".toByteArray() + byteArrayOf(0xff.toByte()) + "\"}".toByteArray()
|
||||
assertThrows(CharacterCodingException::class.java) { parseFeedbackResultEvent(result(text = corrupt)) }
|
||||
assertThrows(Exception::class.java) { parseFeedbackResultEvent(result(text = "{broken}".toByteArray())) }
|
||||
}
|
||||
|
||||
@Test fun committedAckAndCatalogRemainDifferentFromASnapshot() {
|
||||
val ack = "{\"ch\":\"123\",\"message_id\":\"${"ab".repeat(32)}\",\"committed\":true,\"snapshot_pending\":true}"
|
||||
val event = requireNotNull(parseFeedbackResultEvent(result(text = ack.toByteArray())))
|
||||
assertTrue(event.success); assertTrue(event.json.getBoolean("committed")); assertTrue(event.json.getBoolean("snapshot_pending"))
|
||||
val catalog = requireNotNull(parseFeedbackResultEvent(result(text = "{\"catalog\":[]}".toByteArray())))
|
||||
assertTrue(catalog.json.has("catalog")); assertFalse(catalog.json.has("message_id"))
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user