Every comment is reduced to its first sentence plus @param, @return and @throws tags. Comment lines: 20040 to 8526. ktlint 1.8 applied with its default (official Kotlin) style across all modules; 262 files reformatted. The 264 remaining ktlint findings are naming and filename rules, which are code changes, and are left alone. Comments and formatting only. 1208 tests pass, counted from the XML. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
114 lines
3.3 KiB
Kotlin
114 lines
3.3 KiB
Kotlin
package io.flamenet.e2e
|
|
|
|
import org.json.JSONObject
|
|
import javax.crypto.KeyGenerator
|
|
import kotlin.test.Test
|
|
import kotlin.test.assertEquals
|
|
import kotlin.test.assertTrue
|
|
|
|
/**
|
|
* Disappearing messages (§6.11), at the vault.
|
|
*/
|
|
class DisappearingTest {
|
|
private class MapStorage : Vault.Storage {
|
|
private val records = mutableMapOf<String, ByteArray>()
|
|
|
|
override fun read(name: String) = records[name]
|
|
|
|
override fun write(
|
|
name: String,
|
|
bytes: ByteArray,
|
|
) {
|
|
records[name] = bytes
|
|
}
|
|
|
|
override fun delete(name: String) {
|
|
records.remove(name)
|
|
}
|
|
|
|
override fun names() = records.keys.toList()
|
|
}
|
|
|
|
private fun vault() = Vault(MapStorage(), KeyGenerator.getInstance("AES").apply { init(256) }.generateKey())
|
|
|
|
private fun line(
|
|
text: String,
|
|
at: Long,
|
|
) = JSONObject().put("text", text).put("mine", true).put("at", at)
|
|
|
|
private val now = 1_700_000_000_000L
|
|
|
|
@Test
|
|
fun `with no timer nothing is removed`() {
|
|
val v = vault()
|
|
v.append("t", line("ancient", 1L))
|
|
assertEquals(1, v.history("t", now).length())
|
|
}
|
|
|
|
@Test
|
|
fun `messages older than the timer are gone on the next read`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("t", 60)
|
|
v.append("t", line("old", now - 120_000))
|
|
v.append("t", line("fresh", now - 10_000))
|
|
|
|
val kept = v.history("t", now)
|
|
assertEquals(1, kept.length())
|
|
assertEquals("fresh", kept.getJSONObject(0).optString("text"))
|
|
}
|
|
|
|
/** Gone from disk, not merely filtered out of the answer. */
|
|
@Test
|
|
fun `expiry is a deletion, not a filter`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("t", 60)
|
|
v.append("t", line("old", now - 120_000))
|
|
v.history("t", now)
|
|
|
|
// Read again with the timer switched off: an expired message must not
|
|
// come back, which it would if the first read had only hidden it.
|
|
v.saveDisappearSeconds("t", 0)
|
|
assertEquals(0, v.history("t", now).length())
|
|
}
|
|
|
|
/**
|
|
* A message with no timestamp predates the field.
|
|
*/
|
|
@Test
|
|
fun `a message with no timestamp is kept`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("t", 60)
|
|
v.append("t", JSONObject().put("text", "from before").put("mine", true))
|
|
assertEquals(1, v.history("t", now).length())
|
|
}
|
|
|
|
@Test
|
|
fun `the timer is per conversation`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("timed", 60)
|
|
v.append("timed", line("old", now - 120_000))
|
|
v.append("untimed", line("old", now - 120_000))
|
|
|
|
assertEquals(0, v.history("timed", now).length())
|
|
assertEquals(1, v.history("untimed", now).length())
|
|
}
|
|
|
|
@Test
|
|
fun `turning the timer off forgets it`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("t", 3600)
|
|
assertEquals(3600, v.disappearSeconds("t"))
|
|
v.saveDisappearSeconds("t", 0)
|
|
assertEquals(0, v.disappearSeconds("t"))
|
|
}
|
|
|
|
/** Exactly at the boundary the message survives, off-by-one deletes data. */
|
|
@Test
|
|
fun `a message exactly at the cutoff survives`() {
|
|
val v = vault()
|
|
v.saveDisappearSeconds("t", 60)
|
|
v.append("t", line("edge", now - 60_000))
|
|
assertTrue(v.history("t", now).length() == 1)
|
|
}
|
|
}
|