Skip to content

Commit 11304d0

Browse files
authored
Merge pull request #109 from openppg/claude/emulator-screenshot-testing-Z9idh
Add LVGL emulator for UI regression testing with enhanced build support
2 parents 653a437 + 5308d54 commit 11304d0

50 files changed

Lines changed: 1708 additions & 2 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/config.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,25 @@ jobs:
5454
- name: Run Unit Tests
5555
run: platformio test -e native-test
5656

57+
screenshot-tests:
58+
name: Screenshot Regression Tests
59+
runs-on: ubuntu-latest
60+
steps:
61+
- uses: actions/checkout@v6
62+
with:
63+
token: ${{ github.token }}
64+
show-progress: false
65+
- name: Install Dependencies
66+
run: sudo apt-get update && sudo apt-get install -y cmake g++
67+
- name: Build & Run Screenshot Tests
68+
run: ./test/test_screenshots/build_and_run.sh
69+
- name: Upload Screenshots on Failure
70+
if: failure()
71+
uses: actions/upload-artifact@v7
72+
with:
73+
name: screenshot-regression-output
74+
path: test/test_screenshots/output/
75+
5776
pio-build:
5877
name: PlatformIO Build
5978
runs-on: ubuntu-latest

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,6 @@
33
eppg-controller.ino.cpp
44
src/sp140/sp140.ino.cpp
55
diagnostics-logs/
6+
build-screenshot/
7+
test/test_screenshots/output/*.bmp
8+
test/test_screenshots/output/png/

inc/sp140/lvgl/lv_conf.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@
134134
* WIDGET USAGE
135135
*=================*/
136136

137-
#define LV_USE_ANIMIMAGE 0
137+
#define LV_USE_ANIMIMG 0
138138

139139
#define LV_USE_ARC 1
140140

platformio.ini

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,29 @@ build_flags =
8484
-I .pio/libdeps/native-test/CircularBuffer
8585
-D ARDUINO=1
8686
build_src_filter = -<*>
87-
test_ignore = neopixel*
87+
test_ignore = neopixel*, test_screenshots
8888
lib_deps =
8989
ArduinoJson@7.4.3
9090
rlogiacco/CircularBuffer@^1.4.0
91+
92+
[env:native-screenshot]
93+
platform = native
94+
test_framework = googletest
95+
build_type = debug
96+
build_flags =
97+
-I test/screenshot_stubs
98+
-I inc
99+
-I inc/sp140/lvgl
100+
-D LV_CONF_INCLUDE_SIMPLE
101+
-D LV_LVGL_H_INCLUDE_SIMPLE
102+
-D ARDUINO=1
103+
-D NATIVE_SCREENSHOT_TEST=1
104+
-std=c++17
105+
build_src_filter =
106+
-<*>
107+
+<sp140/lvgl/lvgl_main_screen.cpp>
108+
+<sp140/lvgl/lvgl_updates.cpp>
109+
+<sp140/lvgl/lvgl_alerts.cpp>
110+
test_filter = test_screenshots
111+
lib_deps =
112+
lvgl/lvgl@^9.5.0
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
#include "SPI.h"
5+
6+
#define INITR_BLACKTAB 0
7+
#define ST77XX_BLACK 0x0000
8+
9+
class Adafruit_ST7735 {
10+
public:
11+
Adafruit_ST7735(SPIClass* spi, int8_t cs, int8_t dc, int8_t rst) {
12+
(void)spi; (void)cs; (void)dc; (void)rst;
13+
}
14+
void initR(uint8_t) {}
15+
void setRotation(uint8_t) {}
16+
void fillScreen(uint16_t) {}
17+
void setAddrWindow(uint16_t, uint16_t, uint16_t, uint16_t) {}
18+
void writePixels(uint16_t*, uint32_t) {}
19+
void startWrite() {}
20+
void endWrite() {}
21+
};

test/screenshot_stubs/Arduino.h

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
#pragma once
2+
#include <stdint.h>
3+
#include <chrono>
4+
#include <cstring>
5+
#include <cstdio>
6+
#include <cmath>
7+
#include <string>
8+
#include <thread>
9+
10+
// Basic Arduino types and helpers for native screenshot tests
11+
using std::chrono::steady_clock;
12+
using std::chrono::milliseconds;
13+
14+
class String {
15+
public:
16+
String() = default;
17+
String(const char* s) : data_(s ? s : "") {}
18+
bool concat(char c) { data_ += c; return true; }
19+
bool concat(const char* s) { data_ += s ? s : ""; return true; }
20+
const char* c_str() const { return data_.c_str(); }
21+
size_t length() const { return data_.size(); }
22+
private:
23+
std::string data_;
24+
};
25+
26+
struct __FlashStringHelper;
27+
28+
class Print {
29+
public:
30+
virtual ~Print() = default;
31+
virtual size_t write(uint8_t) { return 1; }
32+
virtual size_t write(const uint8_t* buffer, size_t size) { (void)buffer; return size; }
33+
size_t write(const char* s) { return write(reinterpret_cast<const uint8_t*>(s), s ? strlen(s) : 0); }
34+
template <typename... Args> void printf(const char*, Args...) {}
35+
template <typename T> void print(const T&) {}
36+
template <typename T> void println(const T&) {}
37+
void println() {}
38+
};
39+
40+
class Printable {
41+
public:
42+
virtual ~Printable() = default;
43+
virtual size_t printTo(Print&) const { return 0; }
44+
};
45+
46+
class Stream : public Print {
47+
public:
48+
virtual int available() { return 0; }
49+
virtual int read() { return -1; }
50+
virtual size_t readBytes(char* buffer, size_t length) { (void)buffer; (void)length; return 0; }
51+
};
52+
53+
struct DummySerial : public Stream {
54+
inline void begin(unsigned long) {}
55+
};
56+
57+
static DummySerial USBSerial;
58+
static DummySerial Serial;
59+
60+
#ifndef PROGMEM
61+
#define PROGMEM
62+
#endif
63+
64+
#ifndef pgm_read_byte
65+
inline uint8_t pgm_read_byte(const void* p) { return *reinterpret_cast<const uint8_t*>(p); }
66+
#endif
67+
68+
inline unsigned long millis() {
69+
static auto start = steady_clock::now();
70+
return (unsigned long)std::chrono::duration_cast<milliseconds>(steady_clock::now() - start).count();
71+
}
72+
73+
inline void delay(unsigned long ms) {
74+
std::this_thread::sleep_for(std::chrono::milliseconds(ms));
75+
}
76+
77+
typedef uint16_t word;
78+
79+
// FreeRTOS type stubs
80+
typedef void* QueueHandle_t;
81+
typedef void* TaskHandle_t;
82+
83+
// GPIO stubs
84+
#ifndef INPUT
85+
#define INPUT 0
86+
#endif
87+
#ifndef OUTPUT
88+
#define OUTPUT 1
89+
#endif
90+
#ifndef LOW
91+
#define LOW 0
92+
#endif
93+
#ifndef HIGH
94+
#define HIGH 1
95+
#endif
96+
#ifndef F
97+
#define F(x) x
98+
#endif
99+
100+
inline void pinMode(int, int) {}
101+
inline void digitalWrite(int, int) {}
102+
inline int digitalRead(int) { return 0; }
103+
inline int analogRead(int) { return 0; }
104+
inline void analogReadResolution(int) {}
105+
106+
// Math helpers
107+
#ifndef constrain
108+
template <typename T>
109+
inline T constrain(T x, T a, T b) { return x < a ? a : (x > b ? b : x); }
110+
#endif
111+
112+
#ifndef min
113+
template <typename T>
114+
inline T min(T a, T b) { return a < b ? a : b; }
115+
#endif
116+
117+
#ifndef max
118+
template <typename T>
119+
inline T max(T a, T b) { return a > b ? a : b; }
120+
#endif
121+
122+
inline long map(long x, long in_min, long in_max, long out_min, long out_max) {
123+
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
124+
}
125+
126+
// LEDC stubs (ESP32)
127+
inline void ledcAttach(int, int, int) {}
128+
inline void ledcWrite(int, int) {}
129+
inline void ledcDetach(int) {}

test/screenshot_stubs/BMS_CAN.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
// Stub BMS_CAN class for native builds
6+
class BMS_CAN {
7+
public:
8+
static constexpr float TEMP_PROBE_DISCONNECTED = -999.0f;
9+
BMS_CAN() {}
10+
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#pragma once
2+
3+
#include <stdint.h>
4+
5+
// Minimal NimBLE stubs for native builds
6+
class NimBLECharacteristic {
7+
public:
8+
void setValue(const uint8_t*, size_t) {}
9+
void notify() {}
10+
};
11+
12+
class NimBLEServer {
13+
public:
14+
uint16_t getConnectedCount() { return 0; }
15+
};
16+
17+
class NimBLEService {};
18+
class NimBLEAdvertising {};
19+
20+
class NimBLEDevice {
21+
public:
22+
static void init(const char*) {}
23+
static NimBLEServer* createServer() { return nullptr; }
24+
};
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
#include "NimBLEDevice.h"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#pragma once
2+
// Stub - no content needed

0 commit comments

Comments
 (0)