summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-10-05 17:40:34 +0200
committerChristophe Besson <cbesson@gmail.com>2026-10-07 22:22:51 +0200
commit519c47841787ed7a29140df2dfb9c48b47cc414e (patch)
tree13f611ac754d65b3aa7f1d161c1719e95dba7624
parent462d76898a306981fbeac859cd54da1468e80639 (diff)
downloadmeshbay-519c47841787ed7a29140df2dfb9c48b47cc414e.tar.gz
test: read UTF-8 explicitly in the licensing and keyring-vector tests
On Windows a bare `read_text()` or `subprocess.run(text=True)` decodes with the locale's code page (cp1252), not UTF-8. `test_licensing.py` then failed on a byte of the vendored LICENSES.txt, and `test_keyring_vectors.py` decoded the generator's output, which carries CJK test strings, into something that no longer matched keyring.json. Both files are UTF-8; say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--packages/meshbay-hub/tests/test_keyring_vectors.py2
-rw-r--r--packages/meshbay-node/tests/test_licensing.py66
2 files changed, 42 insertions, 26 deletions
diff --git a/packages/meshbay-hub/tests/test_keyring_vectors.py b/packages/meshbay-hub/tests/test_keyring_vectors.py
index 3928965..ee4994d 100644
--- a/packages/meshbay-hub/tests/test_keyring_vectors.py
+++ b/packages/meshbay-hub/tests/test_keyring_vectors.py
@@ -45,7 +45,7 @@ def test_the_file_is_what_the_shipped_keyring_writes():
to either that alters a bundle or a transcript fails here first — which is
the moment to decide whether it is a format change every client must make."""
out = subprocess.run(["node", str(GENERATOR)], capture_output=True, text=True,
- timeout=120, check=True).stdout
+ encoding="utf-8", timeout=120, check=True).stdout
assert json.loads(out) == _vectors(), (
"keyring.js or transcripts.js no longer produce tests/vectors/keyring.json; "
"if the format change is deliberate, regenerate it and update every client")
diff --git a/packages/meshbay-node/tests/test_licensing.py b/packages/meshbay-node/tests/test_licensing.py
index 6e50c80..68eb6bb 100644
--- a/packages/meshbay-node/tests/test_licensing.py
+++ b/packages/meshbay-node/tests/test_licensing.py
@@ -50,7 +50,9 @@ def _notices():
def test_each_python_package_declares_its_licence_and_ships_the_text():
for pkg, (expr, files) in EXPECTED.items():
- project = tomllib.loads((PACKAGES / pkg / "pyproject.toml").read_text())["project"]
+ project = tomllib.loads((PACKAGES / pkg / "pyproject.toml").read_text(encoding="utf-8"))[
+ "project"
+ ]
assert project["license"] == expr, pkg
assert project["license-files"] == files, pkg
for f in files:
@@ -58,35 +60,41 @@ def test_each_python_package_declares_its_licence_and_ships_the_text():
def test_licence_texts_are_the_right_ones():
- agpl = (ROOT / "LICENSE").read_text()
+ agpl = (ROOT / "LICENSE").read_text(encoding="utf-8")
assert "GNU AFFERO GENERAL PUBLIC LICENSE" in agpl and "Version 3" in agpl
# Copies, because a wheel's license-files cannot reach outside its package.
for pkg in ("meshbay-hub", "meshbay-node"):
- assert (PACKAGES / pkg / "LICENSE").read_text() == agpl, pkg
+ assert (PACKAGES / pkg / "LICENSE").read_text(encoding="utf-8") == agpl, pkg
common = PACKAGES / "meshbay-common"
- assert "GNU LESSER GENERAL PUBLIC LICENSE" in (common / "COPYING.LESSER").read_text()
- assert "GNU GENERAL PUBLIC LICENSE" in (common / "COPYING").read_text()
+ assert "GNU LESSER GENERAL PUBLIC LICENSE" in (common / "COPYING.LESSER").read_text(
+ encoding="utf-8"
+ )
+ assert "GNU GENERAL PUBLIC LICENSE" in (common / "COPYING").read_text(encoding="utf-8")
def test_rpm_specs_and_the_client_agree_with_the_packages():
for pkg in ("meshbay-common", "meshbay-hub", "meshbay-node", "meshbay-client"):
- spec = (ROOT / "packaging" / "rpm" / f"{pkg}.spec").read_text()
+ spec = (ROOT / "packaging" / "rpm" / f"{pkg}.spec").read_text(encoding="utf-8")
want = EXPECTED.get(pkg, ("AGPL-3.0-or-later",))[0]
assert re.search(rf"^License:\s+{re.escape(want)}\s*$", spec, re.M), pkg
assert "%license %{_licensedir}/%{name}" in spec, pkg
- pkg_json = json.loads((PACKAGES / "meshbay-client" / "package.json").read_text())
+ pkg_json = json.loads(
+ (PACKAGES / "meshbay-client" / "package.json").read_text(encoding="utf-8")
+ )
assert pkg_json["license"] == "AGPL-3.0-or-later"
def test_every_windows_target_ships_the_licence():
- pkg_json = json.loads((PACKAGES / "meshbay-client" / "package.json").read_text())
+ pkg_json = json.loads(
+ (PACKAGES / "meshbay-client" / "package.json").read_text(encoding="utf-8")
+ )
assert {"from": "../../LICENSE", "to": "LICENSE.txt"} in pkg_json["build"]["win"][
"extraResources"
]
for yml in ("electron-builder.light.yml", "electron-builder.msix.yml"):
- text = (ROOT / "packaging" / "win" / yml).read_text()
+ text = (ROOT / "packaging" / "win" / yml).read_text(encoding="utf-8")
assert "- from: ../../LICENSE\n to: LICENSE.txt" in text, yml
- ps1 = (ROOT / "packaging" / "win" / "build-node-runtime.ps1").read_text()
+ ps1 = (ROOT / "packaging" / "win" / "build-node-runtime.ps1").read_text(encoding="utf-8")
assert "third_party_notices.py" in ps1 and "THIRD-PARTY-NOTICES.txt" in ps1
@@ -118,8 +126,8 @@ def test_notices_follow_what_the_node_actually_ships():
def test_every_vendored_file_has_its_provenance_and_licence():
- provenance = (VENDOR / "PROVENANCE.md").read_text()
- licences = (VENDOR / "LICENSES.txt").read_text()
+ provenance = (VENDOR / "PROVENANCE.md").read_text(encoding="utf-8")
+ licences = (VENDOR / "LICENSES.txt").read_text(encoding="utf-8")
for f in VENDOR.iterdir():
if f.name in ("PROVENANCE.md", "LICENSES.txt"):
continue
@@ -135,17 +143,23 @@ def _sources():
def test_the_lgpl_files_are_exactly_the_ones_that_say_so():
- marked = sorted(f for f in _sources() if f.read_text().startswith(SPDX_LGPL))
+ marked = sorted(f for f in _sources() if f.read_text(encoding="utf-8").startswith(SPDX_LGPL))
assert marked == LGPL_FILES
def test_every_client_carries_the_licence_texts():
"""static/ is the interface of the web, the desktop and Android alike."""
texts = STATIC / "licenses"
- assert (texts / "AGPL-3.0.txt").read_text() == (ROOT / "LICENSE").read_text()
+ assert (texts / "AGPL-3.0.txt").read_text(encoding="utf-8") == (ROOT / "LICENSE").read_text(
+ encoding="utf-8"
+ )
common = PACKAGES / "meshbay-common"
- assert (texts / "LGPL-3.0.txt").read_text() == (common / "COPYING.LESSER").read_text()
- assert (texts / "GPL-3.0.txt").read_text() == (common / "COPYING").read_text()
+ assert (texts / "LGPL-3.0.txt").read_text(encoding="utf-8") == (
+ common / "COPYING.LESSER"
+ ).read_text(encoding="utf-8")
+ assert (texts / "GPL-3.0.txt").read_text(encoding="utf-8") == (common / "COPYING").read_text(
+ encoding="utf-8"
+ )
def _strip_js(src: str) -> str:
@@ -165,27 +179,29 @@ def test_the_lgpl_layer_depends_on_nothing_under_the_agpl():
r"([A-Za-z_$][\w$]*)",
re.M,
)
- defined_in_lgpl = {n for f in lgpl if f.suffix == ".js" for n in top.findall(f.read_text())}
+ defined_in_lgpl = {
+ n for f in lgpl if f.suffix == ".js" for n in top.findall(f.read_text(encoding="utf-8"))
+ }
agpl_globals = {
n: f.name
for f in STATIC.glob("*.js")
if f not in lgpl
- for n in top.findall(f.read_text())
+ for n in top.findall(f.read_text(encoding="utf-8"))
if n not in defined_in_lgpl
}
kt_decl = re.compile(r"^\s*(?:\w+\s+)*(?:class|object|interface)\s+(\w+)", re.M)
defined_in_lgpl_kt = {
- n for f in lgpl if f.suffix == ".kt" for n in kt_decl.findall(f.read_text())
+ n for f in lgpl if f.suffix == ".kt" for n in kt_decl.findall(f.read_text(encoding="utf-8"))
}
agpl_kotlin = {
n: f.name
for f in ANDROID.glob("**/*.kt")
if f not in lgpl
- for n in kt_decl.findall(f.read_text())
+ for n in kt_decl.findall(f.read_text(encoding="utf-8"))
if n not in defined_in_lgpl_kt
}
for f in LGPL_FILES:
- src = f.read_text()
+ src = f.read_text(encoding="utf-8")
if f.suffix == ".kt":
for imp in re.findall(r"^import (org\.meshbay\.[\w.]+)", src, re.M):
owner = (
@@ -216,7 +232,7 @@ REFERENCE_APP = [STATIC / "helloworld-app.js", STATIC / "helloworld-app-settings
def _interface_modules() -> set[str]:
"""The modules the permission names — read from it, the one place they are listed."""
- text = APP_EXCEPTION.read_text()
+ text = APP_EXCEPTION.read_text(encoding="utf-8")
block = text.split("2. the names exported by these modules", 1)[1].split("3.", 1)[0]
return set(re.findall(r"^\s+([\w-]+\.js)\s*$", block, re.M))
@@ -226,7 +242,7 @@ def test_the_application_interface_names_modules_that_exist():
assert modules == {"i18n.js", "icon.js", "file-utils.js", "settings-ui.js", "folder-tree.js"}
for m in modules:
assert (STATIC / m).is_file(), m
- assert not (STATIC / m).read_text().startswith(SPDX_LGPL), (
+ assert not (STATIC / m).read_text(encoding="utf-8").startswith(SPDX_LGPL), (
f"{m} is LGPL already; the permission is for the AGPL part"
)
@@ -239,7 +255,7 @@ def test_the_reference_application_is_free_to_copy_and_stays_inside_the_interfac
"""
allowed = _interface_modules() | {f.name for f in LGPL_FILES if f.parent == STATIC}
for f in REFERENCE_APP:
- src = f.read_text()
+ src = f.read_text(encoding="utf-8")
assert src.startswith("// SPDX-License-Identifier: 0BSD\n"), f.name
for spec in re.findall(r"""^import .* from ['"]\./([^'"]+)['"]""", src, re.M):
assert spec.startswith("vendor/") or spec in allowed, f"{f.name} imports {spec}"
@@ -248,7 +264,7 @@ def test_the_reference_application_is_free_to_copy_and_stays_inside_the_interfac
def test_every_spdx_line_is_one_of_the_known_licences():
for f in _sources():
- first = f.read_text().split("\n", 1)[0]
+ first = f.read_text(encoding="utf-8").split("\n", 1)[0]
if "SPDX-License-Identifier" not in first:
continue
if f in REFERENCE_APP: