test: add portal hardware lifecycle coverage

This commit is contained in:
2026-09-06 20:03:38 +10:00
parent fcd991c5a2
commit d57f6c91c5
15 changed files with 595 additions and 20 deletions
+4
View File
@@ -1012,6 +1012,10 @@ protected:
void failAsyncScan(wm_scan_state_t state, int scanResult = WIFI_SCAN_FAILED);
void resetAsyncScan(bool clearResults);
void invalidateScanResults();
// Release cached scan-result vector capacity after a portal fully closes.
// Do not use this during normal refreshes: the cache is intentionally kept
// while the portal is active so the UI can render nearby networks.
void releaseScanResultStorage();
bool hasFreshScanResults(unsigned int cachetime) const;
bool canRunAsyncScan() const;
void cacheScanResults(int networksFound);
+10
View File
@@ -1373,6 +1373,7 @@ bool WiFiManager::shutdownConfigPortal(){
}
resetAsyncScan(true);
releaseScanResultStorage();
if(!configPortalActive) return false;
@@ -1954,6 +1955,15 @@ void WiFiManager::resetAsyncScan(bool clearResults) {
_scan.visibleNetworkCount = _numNetworks;
}
}
void WiFiManager::releaseScanResultStorage() {
// clear() releases String payloads but deliberately retains the vector's
// backing allocation. At portal shutdown that cache has no remaining value,
// so release it with the server/DNS objects rather than carrying it into the
// normal connected runtime. Keep this out of the refresh path to avoid
// needless allocation churn while a user is looking at nearby networks.
std::vector<WiFiScanNetwork>().swap(_scanResultsCache);
}
void WiFiManager::invalidateScanResults() {
_scan.resultsValid = false;
+9 -11
View File
@@ -16,10 +16,6 @@
#include <cstring>
#if defined(ESP8266) || defined(ESP32)
#ifndef WM_PAGE_RESERVE_BYTES
#define WM_PAGE_RESERVE_BYTES 8192
#endif
static void jsonAppendEscaped(String& out, const String& s) {
for (size_t i = 0; i < s.length(); i++) {
const char c = s[i];
@@ -56,7 +52,7 @@ namespace {
const char kEmptyPortalPlaceholder[] PROGMEM = "";
inline void reservePage(String& page, size_t extraBytes = WM_PAGE_RESERVE_BYTES) {
inline void reservePage(String& page, size_t extraBytes) {
if (extraBytes == 0) return;
const size_t targetLen = page.length() + extraBytes;
(void)page.reserve(targetLen);
@@ -259,21 +255,23 @@ void WiFiManagerHandlers::collectVisibleScanResults(std::vector<const WiFiManage
}
if (_wm->_removeDuplicateAPs) {
std::vector<const WiFiManager::WiFiScanNetwork*> deduped;
deduped.reserve(networks.size());
// Reuse the pointer storage that was already reserved above. Building a
// second vector briefly doubles this request's scan-list allocation on
// constrained ESP8266 heaps.
size_t kept = 0;
for (const auto* network : networks) {
bool duplicate = false;
for (const auto* existing : deduped) {
if (existing->ssid == network->ssid) {
for (size_t i = 0; i < kept; ++i) {
if (networks[i]->ssid == network->ssid) {
duplicate = true;
break;
}
}
if (!duplicate) {
deduped.push_back(network);
networks[kept++] = network;
}
}
networks.swap(deduped);
networks.resize(kept);
}
}