mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-26 18:47:56 +00:00
80 lines
3.9 KiB
Python
80 lines
3.9 KiB
Python
"""Guard the build-local nRF52 SoftDevice flash-completion repair."""
|
|
|
|
from importlib.util import module_from_spec, spec_from_file_location
|
|
from pathlib import Path
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[1]
|
|
SCRIPT = ROOT / "scripts/nrf52_internal_flash_fix.py"
|
|
spec = spec_from_file_location("nrf52_internal_flash_fix", SCRIPT)
|
|
module = module_from_spec(spec)
|
|
spec.loader.exec_module(module)
|
|
|
|
|
|
class Nrf52InternalFlashFixTest(unittest.TestCase):
|
|
def test_wait_cannot_be_optimized_into_immediate_success(self):
|
|
source = ("before\n" + module.OLD_WAIT + " do_wait();\n }\n"
|
|
+ module.OLD_FLUSH + module.OLD_VERIFY + "after\n")
|
|
patched = module.patched_source(source)
|
|
self.assertIn("volatile uint8_t sd_en", patched)
|
|
self.assertIn('''__asm volatile ("" ::: "memory");''', patched)
|
|
self.assertIn("if (sd_en)", patched)
|
|
self.assertIn("mesh_flash_nrf5x_flush_checked", patched)
|
|
self.assertIn("volatile uint8_t const * flash", patched)
|
|
self.assertEqual(module.patched_source(patched), patched)
|
|
|
|
def test_cache_failures_are_sticky_until_checked_sync(self):
|
|
patched = module.patched_cache_source(module.OLD_CACHE_FLUSH)
|
|
self.assertIn("mesh_flash_cache_take_flush_result", patched)
|
|
self.assertIn("mesh_flash_cache_flush_ok = false", patched)
|
|
self.assertIn("fc->program", patched)
|
|
self.assertIn("fc->verify", patched)
|
|
self.assertEqual(module.patched_cache_source(patched), patched)
|
|
|
|
def test_internalfs_propagates_checked_flush_failure(self):
|
|
source = (module.OLD_INTERNAL_READ + module.OLD_INTERNAL_PROG
|
|
+ module.OLD_INTERNAL_ERASE_WRITE + module.OLD_INTERNAL_SYNC)
|
|
patched = module.patched_internal_fs_source(source)
|
|
self.assertIn("== (int) size", patched)
|
|
self.assertIn("mesh_flash_nrf5x_flush_checked() ? 0 : LFS_ERR_IO", patched)
|
|
self.assertEqual(module.patched_internal_fs_source(patched), patched)
|
|
|
|
def test_unrecognized_framework_fails_closed(self):
|
|
with self.assertRaises(RuntimeError):
|
|
module.patched_source("changed SDK layout")
|
|
|
|
def test_all_nrf52_builds_load_fix(self):
|
|
ini = (ROOT / "platformio.ini").read_text(encoding="utf-8")
|
|
self.assertIn("pre:scripts/nrf52_internal_flash_fix.py", ini)
|
|
self.assertIn('"*flash_nrf5x.c"', SCRIPT.read_text())
|
|
self.assertIn('"*flash_cache.c"', SCRIPT.read_text())
|
|
self.assertIn('"*InternalFileSystem.cpp"', SCRIPT.read_text())
|
|
# The hardware-in-loop images intentionally bypass nrf52_base, but
|
|
# still use the same framework and must not regress to its unsafe SVC
|
|
# flash-completion wait.
|
|
for path in (ROOT / "tools/hil/profile_fixed_tx.ini",
|
|
ROOT / "tools/hil/profile_switch.ini"):
|
|
contents = path.read_text(encoding="utf-8")
|
|
self.assertEqual(contents.count("pre:scripts/nrf52_usb_power_fix.py"),
|
|
contents.count("pre:scripts/nrf52_internal_flash_fix.py"),
|
|
str(path))
|
|
for section in contents.split("[env:"):
|
|
if "pre:scripts/nrf52_usb_power_fix.py" in section:
|
|
self.assertIn("pre:scripts/nrf52_internal_flash_fix.py", section)
|
|
|
|
def test_application_softdevice_checks_use_compiler_safe_wrapper(self):
|
|
helper = ROOT / "src/helpers/nrf52/SoftDeviceState.h"
|
|
source = helper.read_text(encoding="utf-8")
|
|
self.assertIn("volatile uint8_t state", source)
|
|
self.assertIn('''__asm volatile ("" ::: "memory");''', source)
|
|
for path in (ROOT / "src", ROOT / "variants", ROOT / "examples/companion_radio"):
|
|
for source_file in path.rglob("*.cpp"):
|
|
self.assertNotIn("sd_softdevice_is_enabled(",
|
|
source_file.read_text(encoding="utf-8"),
|
|
str(source_file))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|