Files
pictureFrame-firmware/test/mocks/Arduino.h
T
football2801 27d01057e4 feat(operation): verify X-Image-Sha256 before painting the panel
Pairs with the server-side header. After streaming the response body to
LittleFS, hash the file with mbedtls/sha256 (hardware-accelerated on
ESP32-S3) and compare against the server's claim. On mismatch:

- Don't update NVS_KEY_IMG_ID, so the next poll reports the old id and
  the server sends 200 again with fresh bytes (natural retry, no extra
  HTTP round-trip in this cycle).
- Don't draw — panel keeps whatever was up before, no garbage on the
  e-ink.
- Raise NVS_KEY_ERR_BORDER so the next healthy 304 paints a clean
  recovery frame with the sync-fail border.

Verification is skipped when the header is absent, so the firmware
stays compatible with any server that hasn't deployed the matching
header yet. mbedtls compiles into a native-test no-op stub (returns
empty hex), so existing native tests don't need a SHA implementation.

Two new tests: FW-17a (mismatch path) and FW-17b (missing header
backward compat). Mock String now has equalsIgnoreCase so the new
comparison compiles in native-test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 19:43:02 -04:00

107 lines
3.4 KiB
C++

#pragma once
#include <string>
#include <cstring>
#include <cstdint>
#include <cstdlib>
#include <algorithm>
#include <sstream>
#include <cctype>
// Minimal String class that mimics Arduino's String for native tests
struct String {
std::string _s;
String() {}
String(const char* s) : _s(s ? s : "") {}
String(const std::string& s) : _s(s) {}
String(int v) { _s = std::to_string(v); }
String(unsigned long v) { _s = std::to_string(v); }
String(long long v) { _s = std::to_string(v); }
String(unsigned long long v) { _s = std::to_string(v); }
const char* c_str() const { return _s.c_str(); }
size_t length() const { return _s.size(); }
bool isEmpty() const { return _s.empty(); }
bool empty() const { return _s.empty(); }
int toInt() const { return _s.empty() ? 0 : std::stoi(_s); }
String substring(size_t from) const { return String(_s.substr(from)); }
String substring(size_t from, size_t to) const { return String(_s.substr(from, to - from)); }
void replace(const char* from, const char* to_str) {
std::string result;
std::string f(from), t(to_str);
size_t pos = 0, found;
while ((found = _s.find(f, pos)) != std::string::npos) {
result += _s.substr(pos, found - pos);
result += t;
pos = found + f.size();
}
result += _s.substr(pos);
_s = result;
}
void toUpperCase() {
for (char& c : _s) c = (char)toupper((unsigned char)c);
}
bool equalsIgnoreCase(const String& o) const {
if (_s.size() != o._s.size()) return false;
for (size_t i = 0; i < _s.size(); i++) {
if (tolower((unsigned char)_s[i]) != tolower((unsigned char)o._s[i])) return false;
}
return true;
}
bool operator==(const String& o) const { return _s == o._s; }
bool operator==(const char* o) const { return _s == o; }
bool operator!=(const String& o) const { return _s != o._s; }
bool operator!=(const char* o) const { return _s != o; }
String operator+(const String& o) const { return String(_s + o._s); }
String operator+(const char* o) const { return String(_s + o); }
String& operator+=(const String& o) { _s += o._s; return *this; }
String& operator+=(const char* o) { _s += o; return *this; }
// Allow use as map key
operator std::string() const { return _s; }
// toString() for IP-like objects that have it
String toString() const { return *this; }
};
inline String operator+(const char* a, const String& b) { return String(std::string(a) + b._s); }
inline String operator+(const std::string& a, const String& b) { return String(a + b._s); }
// Controllable millis and digitalRead for timeout / button tests
extern uint32_t g_millis_value;
extern int g_digital_read_value;
#ifndef LOW
#define LOW 0
#define HIGH 1
#endif
inline unsigned long millis() { return g_millis_value += 10; }
inline void delay(unsigned long) {}
inline void pinMode(int, int) {}
inline int digitalRead(int) { return g_digital_read_value; }
// Color constants (from config.h)
#define COLOR_YELLOW 0x2
#define COLOR_RED 0x3
// Serial mock
struct SerialMock {
void begin(int) {}
void println(const String&) {}
void println(const char*) {}
void println(int) {}
void print(const String&) {}
void print(const char*) {}
void flush() {}
} Serial;
// strtoull is available from <cstdlib> on native