Skip to content
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
af0b0f9
fix: Minor unit test improvements for compatibility
nerdCopter Oct 22, 2025
516e794
Merge remote-tracking branch 'emuflight/master' into 20251020_master_…
nerdCopter Oct 22, 2025
55fee86
fix: Add pragma weak for inputSource_e and fix global variable declar…
nerdCopter Oct 22, 2025
d2278e3
test: Add stub functions to pid_unittest for missing dependencies
nerdCopter Oct 22, 2025
1e98523
fix: Enable Smith Predictor support and fix sensor_gyro_unittest
nerdCopter Oct 22, 2025
150a5a3
fix: Fully initialize motorConfig_t struct in pg_unittest
nerdCopter Oct 22, 2025
744d4a5
fix: refactor PID unit tests to behavioral assertions
nerdCopter Oct 22, 2025
13b6be5
fix: add stubs and fix struct initializations for RC/RX/scheduler uni…
nerdCopter Oct 23, 2025
bf9de7e
fix: add Kalman filter stubs for sensor_gyro_unittest
nerdCopter Oct 23, 2025
2a3d8f5
fix: Restore precision to PID unit tests and fix CRSF tests
nerdCopter Oct 23, 2025
6cdb9af
fix: Add missing stubs and fix API mismatches for tests 31-38
nerdCopter Oct 23, 2025
e04c500
test: fix scheduler_unittest TestQueue array bounds checking
nerdCopter Oct 23, 2025
2a4be84
test: rewrite sensor_gyro Update test and enable GHST test accessor
nerdCopter Oct 23, 2025
6e410dc
test: improve GHST telemetry test infrastructure (tests remain disabled)
nerdCopter Oct 23, 2025
6f0810a
test: add GHST telemetry buffer accessor for unit tests (tests remain…
nerdCopter Oct 23, 2025
9d82748
Merge branch 'master' into 20251020_master_unittests
nerdCopter Oct 23, 2025
28fe747
fix: Address PR review feedback - test code quality improvements
nerdCopter Oct 23, 2025
3bb971e
fix: Address PR review outside diff range comments
nerdCopter Oct 24, 2025
5e3dd58
docs: Add comments to stdarg.h includes explaining requirement
nerdCopter Oct 24, 2025
e403bef
refactor: Add time simulation infrastructure for GHST telemetry tests
nerdCopter Oct 24, 2025
a7866e6
fix: Correct function signatures and improve comment clarity
nerdCopter Oct 24, 2025
ac2c3ed
style: Improve comment clarity and consistency in telemetry tests
nerdCopter Oct 24, 2025
b4d9622
refactor: Address all 8 code review nitpicks for GHST tests
nerdCopter Oct 24, 2025
e6f454c
refactor: Extract scheduler driver lambda to reduce code duplication
nerdCopter Oct 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ obj/
patches/
startup_stm32f10x_md_gcc.s
.idea
tmp/

# script-generated files
docs/Manual.pdf
Expand Down
2 changes: 1 addition & 1 deletion src/main/flight/servos.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
#include "drivers/pwm_output.h"

// These must be consecutive, see 'reversedSources'
enum {
typedef enum {
INPUT_STABILIZED_ROLL = 0,
INPUT_STABILIZED_PITCH,
INPUT_STABILIZED_YAW,
Expand Down
2 changes: 1 addition & 1 deletion src/main/io/rcdevice_cam.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,6 @@ void rcdeviceUpdate(timeUs_t currentTimeUs);
bool rcdeviceIsEnabled(void);

// used for unit test
rcdeviceSwitchState_t switchStates[BOXCAMERA3 - BOXCAMERA1 + 1];
extern rcdeviceSwitchState_t switchStates[BOXCAMERA3 - BOXCAMERA1 + 1];

void rcdeviceSend5KeyOSDCableSimualtionEvent(rcdeviceCamSimulationKeyEvent_e key);
14 changes: 14 additions & 0 deletions src/main/rx/ghst.c
Original file line number Diff line number Diff line change
Expand Up @@ -349,4 +349,18 @@ bool ghstRxIsActive(void)
{
return serialPort != NULL;
}

// Unit test accessor to read telemetry buffer populated by ghstRxWriteTelemetryData()
#ifdef UNITTEST
uint8_t *ghstGetTelemetryBuf(void)
{
return telemetryBuf;
}

uint8_t ghstGetTelemetryBufLen(void)
{
return telemetryBufLen;
}
#endif

#endif
6 changes: 3 additions & 3 deletions src/main/telemetry/ghst.c
Original file line number Diff line number Diff line change
Expand Up @@ -82,12 +82,12 @@ static void ghstInitializeFrame(sbuf_t *dst)
sbufWriteU8(dst, GHST_ADDR_RX);
}

//compiler reports unused
/*
// Unit test accessor function - only used during testing
#ifdef UNITTEST
STATIC_UNIT_TESTED uint8_t *getGhstFrame(){
return ghstFrame;
}
*/
#endif

static void ghstFinalize(sbuf_t *dst)
{
Expand Down
1 change: 1 addition & 0 deletions src/main/telemetry/hott.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,6 +268,7 @@ void hottPrepareEAMResponse(HOTT_EAM_MSG_t *hottEAMMessage) {
static void hottSerialWrite(uint8_t c) {
static uint8_t serialWrites = 0;
serialWrites++;
(void)serialWrites; // Unused - likely debug code. Silence compiler warning.
serialWrite(hottPort, c);
}

Expand Down
12 changes: 10 additions & 2 deletions src/test/unit/arming_prevention_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ extern "C" {
#include "flight/imu.h"
#include "flight/mixer.h"
#include "flight/pid.h"
// pragma weak inputSource_e removed - firmware bug fixed (changed enum to typedef enum)
#include "flight/servos.h"
#include "io/beeper.h"
#include "io/gps.h"
Expand All @@ -44,6 +45,14 @@ extern "C" {
#include "sensors/gyro.h"
#include "telemetry/telemetry.h"

// Global variable definitions
// rcCommand is defined in rc_controls.c when included
extern float rcCommand[4];

// rcData would be defined in rx.c, but since we don't link rx.c,
// we define it here for the test
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];

PG_REGISTER(accelerometerConfig_t, accelerometerConfig, PG_ACCELEROMETER_CONFIG, 0);
PG_REGISTER(blackboxConfig_t, blackboxConfig, PG_BLACKBOX_CONFIG, 0);
PG_REGISTER(gyroConfig_t, gyroConfig, PG_GYRO_CONFIG, 0);
Expand All @@ -55,8 +64,6 @@ extern "C" {
PG_REGISTER(telemetryConfig_t, telemetryConfig, PG_TELEMETRY_CONFIG, 0);
PG_REGISTER(failsafeConfig_t, failsafeConfig, PG_FAILSAFE_CONFIG, 0);

float rcCommand[4];
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
uint16_t averageSystemLoadPercent = 0;
uint8_t cliMode = 0;
uint8_t debugMode = 0;
Expand Down Expand Up @@ -851,4 +858,5 @@ extern "C" {
bool usbCableIsInserted(void) { return false; }
bool usbVcpIsConnected(void) { return false; }
void pinioBoxTaskControl(void) {}
void updateRcRefreshRate(uint16_t) {}
}
18 changes: 18 additions & 0 deletions src/test/unit/atomic_unittest_c.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,32 @@ struct barrierTrace {
int enter, leave;
};

// Cleanup function for atomic barrier testing
static void __atomic_barrier_cleanup(struct barrierTrace **barrier_ptr) {
if (barrier_ptr && *barrier_ptr) {
(*barrier_ptr)->leave++;
}
}

// Macro helper to create unique identifier for each use
#define __ATOMIC_CONCAT(a, b) a ## b
#define __ATOMIC_MAKE_UNIQUE(x, line) __ATOMIC_CONCAT(x, line)
#define __UNIQUE __ATOMIC_MAKE_UNIQUE(__barrier_, __LINE__)

int testAtomicBarrier_C(struct barrierTrace *b0, struct barrierTrace *b1, struct barrierTrace sample[][2]) {
int sIdx = 0;
// replace barrier macros to track barrier invocation
// pass known struct as barrier variable, keep track inside it
#undef ATOMIC_BARRIER_ENTER
#undef ATOMIC_BARRIER_LEAVE
#undef ATOMIC_BARRIER
#define ATOMIC_BARRIER_ENTER(ptr, refStr) do {(ptr)->enter++; } while(0)
#define ATOMIC_BARRIER_LEAVE(ptr, refStr) do {(ptr)->leave++; } while(0)
// For C code, use __cleanup__ to track when we leave scope
#define ATOMIC_BARRIER(data) \
struct barrierTrace *__attribute__((cleanup(__atomic_barrier_cleanup))) __UNIQUE = &(data); \
ATOMIC_BARRIER_ENTER(__UNIQUE, #data); \
do {} while(0)
b0->enter = 0;
b0->leave = 0;
b1->enter = 0;
Expand Down
2 changes: 1 addition & 1 deletion src/test/unit/baro_bmp280_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ typedef struct bmp280_calib_param_s {
int32_t t_fine; /* calibration t_fine data */
} bmp280_calib_param_t;

bmp280_calib_param_t bmp280_cal;
extern bmp280_calib_param_t bmp280_cal;
}


Expand Down
7 changes: 5 additions & 2 deletions src/test/unit/blackbox_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ extern "C" {
#include "sensors/battery.h"
#include "sensors/gyro.h"

// Register required for gyro_sync.c
PG_REGISTER(gyroConfig_t, gyroConfig, PG_GYRO_CONFIG, 0);

extern int16_t blackboxIInterval;
extern int16_t blackboxPInterval;
}
Expand Down Expand Up @@ -368,7 +371,7 @@ uint8_t stateFlags;
const uint32_t baudRates[] = {0, 9600, 19200, 38400, 57600, 115200, 230400, 250000,
400000, 460800, 500000, 921600, 1000000, 1500000, 2000000, 2470000}; // see baudRate_e
uint8_t debugMode;
int32_t blackboxHeaderBudget;
extern int32_t blackboxHeaderBudget;
gpsSolutionData_t gpsSol;
int32_t GPS_home[2];

Expand Down Expand Up @@ -397,7 +400,7 @@ bool isSerialTransmitBufferEmpty(const serialPort_t *) {return false;}
bool feature(uint32_t) {return false;}
void mspSerialReleasePortIfAllocated(serialPort_t *) {}
serialPortConfig_t *findSerialPortConfig(serialPortFunction_e ) {return NULL;}
serialPort_t *findSharedSerialPort(uint16_t , serialPortFunction_e ) {return NULL;}
serialPort_t *findSharedSerialPort(uint32_t, serialPortFunction_e ) {return NULL;}
serialPort_t *openSerialPort(serialPortIdentifier_e, serialPortFunction_e, serialReceiveCallbackPtr, void *, uint32_t, portMode_e, portOptions_e) {return NULL;}
void closeSerialPort(serialPort_t *) {}
portSharing_e determinePortSharing(const serialPortConfig_t *, serialPortFunction_e ) {return PORTSHARING_UNUSED;}
Expand Down
29 changes: 22 additions & 7 deletions src/test/unit/cli_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>

Check warning on line 21 in src/test/unit/cli_unittest.cc

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

src/test/unit/cli_unittest.cc#L21

Include file: <stdarg.h> not found. Please note: Cppcheck does not need standard library headers to get proper results.

#include <limits.h>

Expand Down Expand Up @@ -59,9 +60,12 @@
void cliGet(char *cmdline);
void cliVtx(char *cmdline);

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc99-designator"
const clivalue_t valueTable[] = {
{ "array_unit_test", VAR_INT8 | MODE_ARRAY | MASTER_VALUE, .config.array.length = 3, PG_RESERVED_FOR_TESTING_1, 0 }
};
#pragma GCC diagnostic pop
const uint16_t valueTableEntryCount = ARRAYLEN(valueTable);
const lookupTableEntry_t lookupTables[] = {};

Expand All @@ -85,6 +89,7 @@
PG_REGISTER(pidConfig_t, pidConfig, PG_PID_CONFIG, 0);
PG_REGISTER_WITH_RESET_TEMPLATE(vtxConfig_t, vtxConfig, PG_VTX_CONFIG, 1);
PG_RESET_TEMPLATE(vtxConfig_t, vtxConfig,
.vtxChannelActivationConditions = {},
.halfDuplex = true
);

Expand All @@ -93,6 +98,10 @@

#include "unittest_macros.h"
#include "gtest/gtest.h"

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wc99-designator"

TEST(CLIUnittest, TestCliSet)
{

Expand All @@ -101,6 +110,7 @@
const clivalue_t cval = {
.name = "array_unit_test",
.type = MODE_ARRAY | MASTER_VALUE | VAR_INT8,
.config = {.array.length = 3},
.pgn = PG_RESERVED_FOR_TESTING_1,
.offset = 0
};
Expand Down Expand Up @@ -134,7 +144,7 @@
EXPECT_EQ(900, MODE_STEP_TO_CHANNEL_VALUE(cac6->range.endStep));

// set condition 6
char *str = (char *)"6 6 1 2 3 925 1300";
char str[] = "6 6 1 2 3 925 1300";
cliVtx(str);

EXPECT_EQ(6, cac6->auxChannelIndex);
Expand All @@ -146,7 +156,7 @@
EXPECT_EQ(1300, MODE_STEP_TO_CHANNEL_VALUE(cac6->range.endStep));

// set condition 2
char *str2 = (char *)"2 1 2 3 4 1500 2100";
char str2[] = "2 1 2 3 4 1500 2100";
cliVtx(str2);

const vtxChannelActivationCondition_t *cac2 = &vtxConfig()->vtxChannelActivationConditions[2];
Expand All @@ -160,7 +170,7 @@

// test we can reset existing condition
// by providing 0 vaues, the condition should be reset (and error shown to the user)
char *str3 = (char *)"2 0 0 0 0 0 0";
char str3[] = "2 0 0 0 0 0 0";
cliVtx(str3);

EXPECT_EQ(0, cac2->auxChannelIndex);
Expand All @@ -173,7 +183,7 @@
TEST(CLIUnittest, TestCliVtxInvalidArgumentCount)
{
// cli expects 7 total arguments (condition index + 6 parameters)
char *correctCmd = (char *) "1 1 2 3 4 1000 2000";
char correctCmd[] = "1 1 2 3 4 1000 2000";
cliVtx(correctCmd); // load some data into condition 1
const vtxChannelActivationCondition_t *cac1 = &vtxConfig()->vtxChannelActivationConditions[1];
EXPECT_EQ(1, cac1->auxChannelIndex);
Expand All @@ -182,7 +192,7 @@
EXPECT_EQ(4, cac1->power);
EXPECT_EQ(1000, MODE_STEP_TO_CHANNEL_VALUE(cac1->range.startStep));
EXPECT_EQ(2000, MODE_STEP_TO_CHANNEL_VALUE(cac1->range.endStep));
char *str = (char *)"1 0 0 0 0"; // 5 arguments, should throw an error and reset the line 1
char str[] = "1 0 0 0 0"; // 5 arguments, should throw an error and reset the line 1
cliVtx(str);
EXPECT_EQ(0, cac1->auxChannelIndex);
EXPECT_EQ(0, cac1->band);
Expand All @@ -194,7 +204,7 @@

cliVtx(correctCmd); // load some more data into condition 1 so we have something to reset

char *tooManyArgs = (char *)"1 0 0 0 0 100 200 300"; // 7 arguments, expects 6
char tooManyArgs[] = "1 0 0 0 0 100 200 300"; // 7 arguments, expects 6
cliVtx(tooManyArgs); //should throw an cli error and reset the line 1
EXPECT_EQ(0, cac1->auxChannelIndex);
EXPECT_EQ(0, cac1->band);
Expand All @@ -203,6 +213,9 @@
EXPECT_EQ(900, MODE_STEP_TO_CHANNEL_VALUE(cac1->range.startStep));
EXPECT_EQ(900, MODE_STEP_TO_CHANNEL_VALUE(cac1->range.endStep));
}

#pragma GCC diagnostic pop

// STUBS
extern "C" {

Expand Down Expand Up @@ -257,7 +270,9 @@
int8_t unitTestDataArray[3];

void pgResetFn_unitTestData(int8_t *ptr) {
ptr = &unitTestDataArray[0];
(void)ptr; // Unused parameter
// Reset to default array
memset(unitTestDataArray, 0, sizeof(unitTestDataArray));
}

uint32_t getBeeperOffMask(void) { return 0; }
Expand Down
2 changes: 1 addition & 1 deletion src/test/unit/flight_imu_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ extern "C" {
// STUBS

extern "C" {
boxBitmask_t rcModeActivationMask;
extern boxBitmask_t rcModeActivationMask;
float rcCommand[4];
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
float vGyroStdDevModulus;
Expand Down
2 changes: 1 addition & 1 deletion src/test/unit/ledstrip_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ uint8_t stateFlags = 0;
uint16_t flightModeFlags = 0;
float rcCommand[4];
int16_t rcData[MAX_SUPPORTED_RC_CHANNEL_COUNT];
boxBitmask_t rcModeActivationMask;
extern boxBitmask_t rcModeActivationMask;
gpsSolutionData_t gpsSol;

batteryState_e getBatteryState(void) {
Expand Down
23 changes: 23 additions & 0 deletions src/test/unit/osd_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1134,4 +1134,27 @@ extern "C" {
bool isFlipOverAfterCrashMode(void) {
return false;
}

// CRSF stubs
uint16_t CRSFgetLQ(void) { return 50; }
uint8_t CRSFgetRFMode(void) { return 0; }
uint8_t CRSFgetSnR(void) { return 10; }
uint16_t CRSFgetTXPower(void) { return 100; }
uint8_t CRSFgetRSSI(void) { return 50; }

// OLC stubs
int olc_encode(float lat, float lon, size_t length, char *buf, size_t bufsize) {
(void)lat;
(void)lon;
(void)length;
(void)buf;
(void)bufsize;
return 0;
}

// Flight mode stubs
float getAngleModeAngles(int axis) {
(void)axis;
return 0.0f;
}
}
11 changes: 10 additions & 1 deletion src/test/unit/pg_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,19 @@ extern "C" {
PG_REGISTER_WITH_RESET_TEMPLATE(motorConfig_t, motorConfig, PG_MOTOR_CONFIG, 1);

PG_RESET_TEMPLATE(motorConfig_t, motorConfig,
.dev = {
.motorPwmRate = 400,
.motorPwmProtocol = 0,
.motorPwmInversion = 0,
.useUnsyncedPwm = 0,
.useBurstDshot = 0,
.ioTags = {0}
},
.digitalIdleOffsetValue = 0,
.minthrottle = 1150,
.maxthrottle = 1850,
.mincommand = 1000,
.dev = {.motorPwmRate = 400}
.motorPoleCount = 0
);
}

Expand Down
Loading