From a45e77df1b0024707914a446aa89d33baa223787 Mon Sep 17 00:00:00 2001 From: Christophe Besson Date: Sun, 27 Sep 2026 22:21:26 +0200 Subject: test: make both suites pass on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Most of these failed on Windows for reasons that had nothing to do with the code under test, which is how real Windows defects hid among them: - Read and write files as UTF-8, and talk to Node in UTF-8. read_text(), write_text() and subprocess text=True use the locale codepage, cp1252 on Windows: "é", "—" and "→" arrived as "?" or crashed, some sixty tests. Calls to PowerShell and schtasks are left alone -- they answer in the console codepage. - Import ESM harness modules by file URL (as_uri): a raw "C:\..." path is not a module specifier. - test_cli_golden: mask the tmp path in its JSON-escaped form, spell it the POSIX way, record on Linux, mask the protocol version (the recording had failed everywhere since the MNP 4.0 bump) and argparse's version-dependent quoting; point USERPROFILE at the tmp home, or `member invite` and `operator pair` wrote their codes into the developer's profile. - test_disk_io_off_loop: expect what a free loop can reach on the platform's timer, 15.6 ms on Windows, not an assumed 5 ms. - test_root_paths_are_operator_only: expect the OS's spelling of the path. - test_audio_meta_cache: find ffprobe with shutil.which. Node suite on Windows: 1489 passed, none failed. Hub suite: 3 failures left, all older than this change (two SQLite concurrency tests, one transfer resume). Co-Authored-By: Claude Opus 5.5 --- packages/meshbay-hub/tests/test_transfers.py | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) (limited to 'packages/meshbay-hub/tests/test_transfers.py') diff --git a/packages/meshbay-hub/tests/test_transfers.py b/packages/meshbay-hub/tests/test_transfers.py index b1bac4a..1d0c0f0 100644 --- a/packages/meshbay-hub/tests/test_transfers.py +++ b/packages/meshbay-hub/tests/test_transfers.py @@ -26,15 +26,15 @@ pytestmark = pytest.mark.skipif( def _run(body, tmp_path): module = tmp_path / "transfers.mjs" - module.write_text(TRANSFERS.read_text()) + module.write_text(TRANSFERS.read_text(encoding="utf-8"), encoding="utf-8") script = tmp_path / "case.mjs" script.write_text( - f"import {{ TransferStore, formatSpeed }} from '{module.as_posix()}';\n" + f"import {{ TransferStore, formatSpeed }} from '{module.as_uri()}';\n" "const out = [];\n" "const say = (...a) => out.push(...a);\n" f"{body}\n" - "console.log(JSON.stringify(out));\n") - proc = subprocess.run(["node", str(script)], capture_output=True, text=True) + "console.log(JSON.stringify(out));\n", encoding="utf-8") + proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8") assert proc.returncode == 0, proc.stderr return json.loads(proc.stdout) @@ -388,11 +388,11 @@ def test_asking_for_a_slot_on_a_dead_channel_does_not_throw(tmp_path): # first time it arms its watchdog. start = src.index("const LEASE_WATCHDOG_MS") end = src.index("\nclass MeshBayTransport") - module.write_text(src[start:end] + "\nexport { Lease };\n") + module.write_text(src[start:end] + "\nexport { Lease };\n", encoding="utf-8") script = tmp_path / "case.mjs" script.write_text(f""" -import {{ Lease }} from '{module.as_posix()}'; +import {{ Lease }} from '{module.as_uri()}'; const out = []; const transport = {{ supportsTransferSlots: true, @@ -409,8 +409,8 @@ try {{ lease.release('cancelled'); out.push('release ok'); }} catch (e) {{ out.push('release threw: ' + e.message); }} clearTimeout(lease._watchdog); console.log(JSON.stringify(out)); -""") - proc = subprocess.run(["node", str(script)], capture_output=True, text=True) +""", encoding="utf-8") + proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8") assert proc.returncode == 0, proc.stderr out = json.loads(proc.stdout) assert out[0] is None, f"asking for a slot threw: {out[0]}" @@ -433,7 +433,7 @@ def test_the_slot_is_asked_for_after_there_is_somewhere_to_write(): Source-reading, because the ordering is the whole property and it has no behaviour of its own to drive: what matters is which call comes first. """ - src = (STATIC / "file-utils.js").read_text() + src = (STATIC / "file-utils.js").read_text(encoding="utf-8") fn = src[src.index("async function downloadEntry"):] fn = fn[:fn.index("\n}\n")] # `_openTargetInTurn` since target openings were serialised — same call, @@ -832,7 +832,7 @@ def test_a_paused_transfer_is_not_filed_under_finished(tmp_path): here: a copy of them in this file would agree with a broken version by construction. """ - src = (STATIC / "app.js").read_text() + src = (STATIC / "app.js").read_text(encoding="utf-8") start = src.index(" const running = items.filter(") block = src[start:src.index("const active =", start)] @@ -851,8 +851,8 @@ const items = [ const seen = { running, waiting, paused, finished }; console.log(JSON.stringify(Object.fromEntries( Object.entries(seen).map(([k, v]) => [k, v.map(i => i.id)])))); -""") - proc = subprocess.run(["node", str(script)], capture_output=True, text=True) +""", encoding="utf-8") + proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8") assert proc.returncode == 0, proc.stderr groups = json.loads(proc.stdout) @@ -870,7 +870,7 @@ def test_a_paused_transfer_still_counts_as_active(tmp_path): """The badge says how much is going on. A paused transfer is not over — the person means to come back to it — so counting it as nothing would be a panel that says "0" over work that is still there.""" - src = (STATIC / "app.js").read_text() + src = (STATIC / "app.js").read_text(encoding="utf-8") start = src.index(" const running = items.filter(") block = src[start:src.index("\n\n", src.index("const active =", start))] @@ -879,8 +879,8 @@ def test_a_paused_transfer_still_counts_as_active(tmp_path): const items = [{ id: 1, status: 'paused' }, { id: 2, status: 'done' }]; """ + block + """ console.log(JSON.stringify({ active })); -""") - proc = subprocess.run(["node", str(script)], capture_output=True, text=True) +""", encoding="utf-8") + proc = subprocess.run(["node", str(script)], capture_output=True, text=True, encoding="utf-8") assert proc.returncode == 0, proc.stderr assert json.loads(proc.stdout)["active"] == 1 @@ -897,7 +897,7 @@ def test_a_row_that_cannot_pause_says_so_where_the_button_would_be(): Shown only where a folder can actually be chosen: Firefox and Safari have none to choose, and "choose a folder" would be advice that cannot be taken. """ - src = (STATIC / "app.js").read_text() + src = (STATIC / "app.js").read_text(encoding="utf-8") row = src[src.index("function TransferRow"):] row = row[:row.index("\n}\n")] @@ -917,4 +917,4 @@ def test_the_reason_is_translated_everywhere(): """`t()` falls back to the key, so a missing catalogue entry shows `transfers.not_pausable` in a tooltip rather than a sentence.""" for path in sorted((STATIC / "locales").glob("*.js")): - assert "'transfers.not_pausable'" in path.read_text(), path.name + assert "'transfers.not_pausable'" in path.read_text(encoding="utf-8"), path.name -- cgit v1.2.3