"""Host coverage for physical-page retirement in nRF52 internal ExtraFS.""" from pathlib import Path import subprocess import tempfile import unittest ROOT = Path(__file__).resolve().parents[1] class InternalExtraFsPageMapTest(unittest.TestCase): def test_mapping_skips_whole_bad_pages_and_keeps_legacy_identity_layout(self): source = r""" #include #include using mesh::storage::countInternalExtraFsBadPages; using mesh::storage::internalExtraFsPhysicalPage; int main() { for (uint32_t p = 0; p < 25; ++p) { if (internalExtraFsPhysicalPage(0, p) != p) return 1; } if (internalExtraFsPhysicalPage(0, 25) != UINT32_MAX) return 2; const uint32_t middle = 1UL << 12; if (countInternalExtraFsBadPages(middle) != 1) return 3; if (internalExtraFsPhysicalPage(middle, 11) != 11) return 4; if (internalExtraFsPhysicalPage(middle, 12) != 13) return 5; if (internalExtraFsPhysicalPage(middle, 23) != 24) return 6; if (internalExtraFsPhysicalPage(middle, 24) != UINT32_MAX) return 7; const uint32_t edges = (1UL << 0) | (1UL << 24); if (internalExtraFsPhysicalPage(edges, 0) != 1) return 8; if (internalExtraFsPhysicalPage(edges, 22) != 23) return 9; if (internalExtraFsPhysicalPage(edges, 23) != UINT32_MAX) return 10; const uint32_t four = (1UL << 0) | (1UL << 4) | (1UL << 17) | (1UL << 24); if (countInternalExtraFsBadPages(four) != 4) return 11; uint32_t previous = 0; for (uint32_t logical = 0; logical < 21; logical++) { const uint32_t physical = internalExtraFsPhysicalPage(four, logical); if (physical >= 25 || (four & (1UL << physical))) return 12; if (logical && physical <= previous) return 13; previous = physical; } if (internalExtraFsPhysicalPage(four, 21) != UINT32_MAX) return 14; if (internalExtraFsPhysicalPage(1UL << 25, 0) != UINT32_MAX) return 15; return 0; } """ with tempfile.TemporaryDirectory() as temp_dir: executable = Path(temp_dir) / "extrafs_page_map" compiled = subprocess.run( ["c++", "-std=c++11", f"-I{ROOT / 'src'}", "-x", "c++", "-", "-o", str(executable)], input=source, text=True, capture_output=True, ) self.assertEqual(compiled.returncode, 0, compiled.stderr) executed = subprocess.run([str(executable)], capture_output=True, text=True) self.assertEqual(executed.returncode, 0, executed.stderr) def test_destructive_scan_only_runs_during_early_boot(self): store = (ROOT / "examples/companion_radio/DataStore.cpp").read_text() mesh = (ROOT / "examples/companion_radio/MyMesh.cpp").read_text() device = (ROOT / "examples/companion_radio/ResilientInternalExtraFS.cpp").read_text() device_header = ( ROOT / "examples/companion_radio/ResilientInternalExtraFS.h" ).read_text() self.assertIn("reinitializeInternalExtraFS(true)", store) self.assertIn("scan_physical_pages && !extra->scanAndRetireBadPages()", store) self.assertIn("extra->requestBootScan(true)", store) self.assertIn("setBootScanRequest(marker)", device) self.assertIn("BOOT_SCAN_ALL", device) self.assertIn("BOOT_SCAN_BAD_PAGE_BASE = 0x20", device_header) self.assertIn("BOOT_SCAN_REPEAT = 0x3E", device_header) self.assertIn("BOOT_SCAN_ALL = 0x3F", device_header) self.assertNotIn("BOOT_SCAN_REPEAT_BASE", device_header) page_markers = set(range(0x20, 0x20 + 25)) recovery_markers = page_markers | {0x3E, 0x3F} ota_markers = {0x51, 0x53, 0xA6, 0xD4, 0xED} ota_markers.update(range(0x90, 0xA0)) ota_markers.update(range(0xB1, 0xC0)) ota_markers.update(range(0xC1, 0xCA)) self.assertFalse(recovery_markers & ota_markers) self.assertIn("uint32_t bad = _bad_pages;", device) self.assertNotIn("_bad_pages | (_pending_pages & PAGE_MASK)", device) self.assertIn("return _boot_scan_forced ||", device_header) self.assertIn("extra->acknowledgeRecoveredBootHint()", store) self.assertIn("extra->pageMapNeedsSave()", store) scan_command = mesh.split("void MyMesh::scanInternalExtraFS(Stream& output)", 1)[1] scan_command = scan_command.split("#if defined(MESHCORE_EXTRAFS_HIL)", 1)[0] self.assertIn("_store->requestInternalExtraFSBootScan()", scan_command) self.assertNotIn("scanAndRetireBadPages", scan_command) if __name__ == "__main__": unittest.main()