""" Downloads in the Android application, pinned by reading the source. The page's contract with a native save target is platform.js `nativeSave`: a sink with write/close/abort, an `open` only when the target can open the file, and nothing that names a path. The Android sink keeps it; what it may open is downloads.js `OPENABLE`, held equal here because a second copy of a list of safe types is how an `.html` gets opened one day. """ import re from pathlib import Path import pytest from spa_source import STATIC PACKAGES = Path(__file__).resolve().parents[2] MAIN = PACKAGES / "meshbay-android" / "app" / "src" / "main" SAVE = MAIN / "kotlin" / "org" / "meshbay" / "client" / "save" SHIM = MAIN / "assets" / "bridge" / "meshbay-bridge.js" pytestmark = pytest.mark.skipif(not SAVE.exists(), reason="android sources not present") def _read(path: Path) -> str: return path.read_text(encoding="utf-8") def test_what_may_be_opened_is_the_pages_list(): js = _read(STATIC / "downloads.js").split("const OPENABLE = {", 1)[1].split("};", 1)[0] kt = _read(SAVE / "SaveNames.kt").split("val OPENABLE = mapOf(", 1)[1].split("\n )", 1)[0] page = {k: v.split(";")[0] for k, v in re.findall(r"(\w+): '([^']+)'", js)} android = dict(re.findall(r'"(\w+)" to "([^"]+)"', kt)) assert page and android == page, set(android.items()) ^ set(page.items()) def test_open_is_offered_only_where_the_target_says_so(): shim = _read(SHIM) save = shim.split("saveFile: async", 1)[1].split("\n },", 1)[0] assert "if (handle.openable) sink.open" in save sinks = _read(SAVE / "SaveSinks.kt") assert '.put("openable", SaveNames.openableType(shown) != null)' in sinks opening = sinks.split("fun open(id: Long)", 1)[1].split("\n }", 1)[0] assert "SaveNames.openableType(name) ?: throw Refused" in opening def test_the_page_is_told_names_never_uris(): sinks = _read(SAVE / "SaveSinks.kt") for fn in ("fun chooseFolder", "fun getFolder", "fun begin"): body = sinks.split(fn, 1)[1].split("\n fun ", 1)[0] returned = re.findall(r'put\("(\w+)"', body) assert not {"uri", "path", "tree"} & set(returned), (fn, returned) assert "return displayName(treeDocument(tree))" in sinks def test_the_save_channels_are_the_desktops(): preload = _read(PACKAGES / "meshbay-client" / "src" / "preload.js") shim = _read(SHIM) def channels(text: str, call: str) -> set[str]: return set(re.findall(rf"{call}\('((?:save|folder):[\w:-]+)'", text)) assert channels(shim, "call") == channels(preload, r"ipcRenderer\.invoke") assert "nativeSave: true" in shim def test_an_unfinished_file_never_carries_the_final_name(): sinks = _read(SAVE / "SaveSinks.kt") assert '"$wanted.part"' in sinks assert "MediaStore.MediaColumns.IS_PENDING, 1" in sinks assert "MediaStore.MediaColumns.IS_PENDING, 0" in sinks abort = sinks.split("fun abort(id: Long)", 1)[1].split("\n }", 1)[0] assert "delete(sink.uri)" in abort assert "fun cleanUpAfterAKilledProcess" in sinks assert "saves.cleanUpAfterAKilledProcess()" in _read( MAIN / "kotlin" / "org" / "meshbay" / "client" / "MainActivity.kt") def test_a_chosen_folder_that_has_gone_is_not_silently_replaced(): begin = _read(SAVE / "SaveSinks.kt").split("fun begin(", 1)[1].split("\n fun ", 1)[0] assert "auto && !(configuredTree != null && tree == null)" in begin def test_writes_are_binary_and_awaited(): shim = _read(SHIM) assert "head.setUint32(0, 0x4d424231)" in shim assert "port.postMessage(frame)" in shim bridge = _read(MAIN / "kotlin" / "org" / "meshbay" / "client" / "bridge" / "Bridge.kt") before = bridge.split("TYPE_ARRAY_BUFFER", 1)[0] assert "!isMainFrame" in before, "a binary message must pass the same sender check"