package io.flamenet.e2e import org.json.JSONObject import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertTrue /** * The `ctl` flag, as all three engines actually write it. * * 🔴 **This engine wrote `"ctl":true` and the specification says `"ctl":1`.** * That was not a cosmetic disagreement. iOS decodes the field as a number * through a synthesised `Codable`, so a boolean did not fail to set the flag — * it failed the whole envelope's decode and dropped the message onto the * plain-text path. An Android user turning on disappearing messages therefore * sent an iPhone a bubble containing raw JSON, and the timer was never applied * at that end. Nothing caught it because each engine parsed what it had written * itself, and the piece-level tests on both sides passed. */ class ControlFlagInteropTest { @Test fun `a disappearing envelope carries the number the spec asks for`() { val envelope = JSONObject(Content.disappearing(3600)) assertEquals(1, envelope.get("ctl"), "the spec says {\"fnc\":1,\"kind\":\"…\",\"ctl\":1}") assertEquals(3600, envelope.getInt("secs")) assertEquals(1, envelope.getInt("fnc")) } /** And it still parses here, which is the half that already worked. */ @Test fun `our own disappearing envelope round trips`() { val content = Content.parse(Content.disappearing(900)) assertEquals(900, Content.disappearSeconds(content)) assertTrue(content.isControl) } /** * ⚠️ Both shapes are accepted on the way IN. `org.json`'s `optBoolean` does * not coerce a number, so reading only that missed every `"ctl":1` the * other two engines send — and reading only the number would miss the * `true` this engine itself wrote, which is on phones now and cannot be * recalled. */ @Test fun `both spellings of the flag are understood`() { for (spelling in listOf("1", "true")) { val raw = """{"fnc":1,"kind":"some_future_thing","ctl":$spelling}""" assertTrue(Content.parse(raw).isControl, "a control envelope written as ctl:$spelling was shown to the user") } } /** * 🔴 The point of the flag: a control kind from a NEWER peer must be * swallowed, not rendered. Without it, every control kind added after a * given release shows in that release as a bubble the person cannot act on. */ @Test fun `an unknown control kind is swallowed rather than shown`() { val content = Content.parse("""{"fnc":1,"kind":"invented_next_year","ctl":1}""") assertTrue(content.isControl) assertTrue(!content.isRenderable, "control traffic must not reach the thread") } /** An ordinary message is untouched by any of it. */ @Test fun `a plain message is not control traffic`() { assertTrue(!Content.parse("just a message").isControl) assertTrue(!Content.parse(Content.text("hello")).isControl) } }