Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5365557
Fix invalid C99 array initialization
Nov 3, 2025
f2a92b1
Arduino compatibility fix on println()
Nov 3, 2025
a2d250e
Mock SPI and Wire libraries.
Nov 3, 2025
343a766
Fix missing #include (references sprintf)
Nov 3, 2025
a13eb42
Fix inconsistent typing (data is a uint8_t)
Nov 3, 2025
35c553c
Add missing #include (references ::random() from base arduino)
Nov 3, 2025
c06e197
Use the adafruit LittleFS filesystem API when compiling for native.
Nov 3, 2025
77c9c3d
add test invocation to build.sh
Nov 3, 2025
6eb34a7
Enable (native) unit testing.
Nov 3, 2025
28b4916
Explain common vs native
Nov 3, 2025
215f956
Fix suite/test arg ordering
Nov 4, 2025
504bb65
more test coverage on mesh::Util
Nov 4, 2025
de0dcfd
test parseTextParts
Nov 4, 2025
1cf4b7e
Cover more of mesh::Utils
Nov 4, 2025
0912f1f
Add a native-asan env with address sanitization checks.
Nov 4, 2025
f7e618a
Move main() to its own file so it doesn't get copied to other test su…
Nov 4, 2025
cab8938
Initial mesh::Identity tests (constructors)
Nov 4, 2025
996fb1d
Group the mock streams together
Nov 4, 2025
ca0de95
Test Identity::writeTo()
Nov 4, 2025
9785cc6
mesh::LocalIdentity initializer tests
Nov 4, 2025
1103078
Exerise mesh::LocalIdentity loading/saving
Nov 4, 2025
5c28491
Fix an asan catch (in the test code)
Nov 4, 2025
9784c98
Slightly smarter MockStream that can act like a std::string
Nov 6, 2025
ebcf3e0
Merge branch 'dev' of https://github.com/meshcore-dev/MeshCore into t…
Apr 25, 2026
d21960f
Merge branch 'dev' into testing
aqua Apr 25, 2026
d67f429
Merge branch 'testing' of github.com:aqua/meshcore into testing
Apr 25, 2026
2ddaaed
Fix undefined size_t
Apr 28, 2026
759d8b8
Fix test breakers
Apr 28, 2026
f9d8bcf
Don't use STREQ on strings that aren't guaranteed to be null-terminates
Apr 28, 2026
bf6dbc0
Don't include CayenneLPP when building native for tests.
Apr 28, 2026
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
3 changes: 2 additions & 1 deletion arch/stm32/Adafruit_LittleFS_stm32/src/Adafruit_LittleFS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ bool Adafruit_LittleFS::mkdir (char const *filepath)
// make intermediate parent directory(ies)
while ( NULL != (slash = strchr(slash, '/')) )
{
char parent[slash - filepath + 1] = { 0 };
char parent[slash - filepath + 1];
parent[0] = 0;
memcpy(parent, filepath, slash - filepath);

int rc = lfs_mkdir(&_lfs, parent);
Expand Down
55 changes: 37 additions & 18 deletions build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Commands:
build-companion-firmwares: Build all companion firmwares for all build targets.
build-repeater-firmwares: Build all repeater firmwares for all build targets.
build-room-server-firmwares: Build all chat room server firmwares for all build targets.
test: Run test on the given target (typically 'native')

Examples:
Build firmware for the "RAK_4631_repeater" device target
Expand Down Expand Up @@ -89,6 +90,27 @@ get_pio_envs_ending_with_string() {
done
}

set_build_env() {
# get git commit sha
COMMIT_HASH=$(git rev-parse --short HEAD)

# set firmware build date
FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y')

# get FIRMWARE_VERSION, which should be provided by the environment
if [ -z "$FIRMWARE_VERSION" ]; then
echo "FIRMWARE_VERSION must be set in environment"
exit 1
fi

# set firmware version string
# e.g: v1.0.0-abcdef
FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION}-${COMMIT_HASH}"

# add firmware version info to end of existing platformio build flags in environment vars
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"
}

# get platform flag for a given environment
# $1 should be the environment name
get_platform_for_env() {
Expand Down Expand Up @@ -120,29 +142,12 @@ build_firmware() {
# get env platform for post build actions
ENV_PLATFORM=($(get_platform_for_env $1))

# get git commit sha
COMMIT_HASH=$(git rev-parse --short HEAD)

# set firmware build date
FIRMWARE_BUILD_DATE=$(date '+%d-%b-%Y')

# get FIRMWARE_VERSION, which should be provided by the environment
if [ -z "$FIRMWARE_VERSION" ]; then
echo "FIRMWARE_VERSION must be set in environment"
exit 1
fi

# set firmware version string
# e.g: v1.0.0-abcdef
FIRMWARE_VERSION_STRING="${FIRMWARE_VERSION}-${COMMIT_HASH}"
set_build_env

# craft filename
# e.g: RAK_4631_Repeater-v1.0.0-SHA
FIRMWARE_FILENAME="$1-${FIRMWARE_VERSION_STRING}"

# add firmware version info to end of existing platformio build flags in environment vars
export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DFIRMWARE_BUILD_DATE='\"${FIRMWARE_BUILD_DATE}\"' -DFIRMWARE_VERSION='\"${FIRMWARE_VERSION_STRING}\"'"

# disable debug flags if requested
disable_debug_flags

Expand Down Expand Up @@ -245,6 +250,18 @@ build_firmwares() {
build_room_server_firmwares
}

run_tests() {
envs=($(get_pio_envs_containing_string "$1"))
for env in "${envs[@]}"; do
run_test $env
done
}

run_test() {
set_build_env
pio test -e $1
}

# clean build dir
rm -rf out
mkdir -p out
Expand Down Expand Up @@ -275,4 +292,6 @@ elif [[ $1 == "build-repeater-firmwares" ]]; then
build_repeater_firmwares
elif [[ $1 == "build-room-server-firmwares" ]]; then
build_room_server_firmwares
elif [[ $1 == "test" ]] ; then
run_tests "$2"
fi
27 changes: 27 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -151,3 +151,30 @@ lib_deps =
stevemarple/MicroNMEA @ ^2.0.6
adafruit/Adafruit BME680 Library @ ^2.0.4
adafruit/Adafruit BMP085 Library @ ^1.2.4

; ----------------- Native (for tests) -----------------
[env]
test_framework = googletest
test_speed = 115200

[env:native]
platform = native
lib_compat_mode = off
test_build_src = true
lib_deps =
${arduino_base.lib_deps}
skaygin/ArduinoNative
file://arch/stm32/Adafruit_LittleFS_stm32
file://test/mocks/Wire
file://test/mocks/SPI
build_flags = ${arduino_base.build_flags}
-D_USE_MATH_DEFINES -DNATIVE_PLATFORM -DINPUT_PULLDOWN=0x3
build_src_filter = ${arduino_base.build_src_filter}
-<helpers/AutoDiscoverRTCClock.cpp>

[env:native-asan]
extends = env:native
platform = native
build_flags = ${env:native.build_flags}
-fsanitize=address
-fsanitize=bounds
6 changes: 3 additions & 3 deletions src/Identity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ bool LocalIdentity::writeTo(Stream& s) const {
}

void LocalIdentity::printTo(Stream& s) const {
s.print("pub_key: "); Utils::printHex(s, pub_key, PUB_KEY_SIZE); s.println();
s.print("prv_key: "); Utils::printHex(s, prv_key, PRV_KEY_SIZE); s.println();
s.print("pub_key: "); Utils::printHex(s, pub_key, PUB_KEY_SIZE); s.println("");
s.print("prv_key: "); Utils::printHex(s, prv_key, PRV_KEY_SIZE); s.println("");
}

size_t LocalIdentity::writeTo(uint8_t* dest, size_t max_len) {
Expand Down Expand Up @@ -140,4 +140,4 @@ void LocalIdentity::calcSharedSecret(uint8_t* secret, const uint8_t* other_pub_k
ed25519_key_exchange(secret, other_pub_key, prv_key);
}

}
}
1 change: 1 addition & 0 deletions src/MeshCore.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once

#include <stdint.h>
#include <stddef.h>
#include <math.h>

#define MAX_HASH_SIZE 8
Expand Down
3 changes: 2 additions & 1 deletion src/helpers/AdvertDataHelpers.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include <helpers/AdvertDataHelpers.h>
#include <stdio.h>

uint8_t AdvertDataBuilder::encodeTo(uint8_t app_data[]) {
app_data[0] = _type;
Expand Down Expand Up @@ -84,4 +85,4 @@ void AdvertTimeHelper::formatRelativeTimeDiff(char dest[], int32_t seconds_from_
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/helpers/ClientACL.cpp
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#include "ClientACL.h"

static File openWrite(FILESYSTEM* _fs, const char* filename) {
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
_fs->remove(filename);
return _fs->open(filename, FILE_O_WRITE);
#elif defined(RP2040_PLATFORM)
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/CommonCLI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) {
}

void CommonCLI::savePrefs(FILESYSTEM* fs) {
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
fs->remove("/com_prefs");
File file = fs->open("/com_prefs", FILE_O_WRITE);
#elif defined(RP2040_PLATFORM)
Expand Down
4 changes: 2 additions & 2 deletions src/helpers/IdentityStore.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id) {
char filename[40];
sprintf(filename, "%s/%s.id", _dir, name);

#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
_fs->remove(filename);
File file = _fs->open(filename, FILE_O_WRITE);
#elif defined(RP2040_PLATFORM)
Expand All @@ -68,7 +68,7 @@ bool IdentityStore::save(const char *name, const mesh::LocalIdentity& id, const
char filename[40];
sprintf(filename, "%s/%s.id", _dir, name);

#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
_fs->remove(filename);
File file = _fs->open(filename, FILE_O_WRITE);
#elif defined(RP2040_PLATFORM)
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/IdentityStore.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#if defined(ESP32) || defined(RP2040_PLATFORM)
#include <FS.h>
#define FILESYSTEM fs::FS
#elif defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#elif defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
#include <Adafruit_LittleFS.h>
#define FILESYSTEM Adafruit_LittleFS

Expand Down
10 changes: 4 additions & 6 deletions src/helpers/RegionMap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ static const char* skip_hash(const char* name) {
}

static File openWrite(FILESYSTEM* _fs, const char* filename) {
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM)
#if defined(NRF52_PLATFORM) || defined(STM32_PLATFORM) || defined(NATIVE_PLATFORM)
_fs->remove(filename);
return _fs->open(filename, FILE_O_WRITE);
#elif defined(RP2040_PLATFORM)
Expand Down Expand Up @@ -287,11 +287,9 @@ void RegionMap::printChildRegions(int indent, const RegionEntry* parent, Stream&
out.print(' ');
}

if (parent->flags & REGION_DENY_FLOOD) {
out.printf("%s%s\n", skip_hash(parent->name), parent->id == home_id ? "^" : "");
} else {
out.printf("%s%s F\n", skip_hash(parent->name), parent->id == home_id ? "^" : "");
}
out.print(skip_hash(parent->name));
out.print(parent->id == home_id ? "^" : "");
out.println(parent->flags & REGION_DENY_FLOOD ? "" : " F");

for (int i = 0; i < num_regions; i++) {
auto r = &regions[i];
Expand Down
4 changes: 4 additions & 0 deletions src/helpers/SensorManager.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
#pragma once

#ifdef NATIVE_PLATFORM
struct CayenneLPP; // Work around a clash between CayenneLPP & ArduinoNative
#else
#include <CayenneLPP.h>
#endif
#include "sensors/LocationProvider.h"

#define TELEM_PERM_BASE 0x01 // 'base' permission includes battery
Expand Down
1 change: 1 addition & 0 deletions src/helpers/radiolib/RadioLibWrappers.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include <Mesh.h>
#include <RadioLib.h>
#include <Arduino.h>

class RadioLibWrapper : public mesh::Radio {
protected:
Expand Down
44 changes: 44 additions & 0 deletions test/mocks/SPI/SPI.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#ifndef SPI_H
#define SPI_H

typedef int BitOrder;


typedef enum {
SPI_MODE0 = 0,
SPI_MODE1 = 1,
SPI_MODE2 = 2,
SPI_MODE3 = 3,
} SPIMode;

class SPISettings {
public:
SPISettings(uint32_t clock, BitOrder bitOrder, SPIMode dataMode) {}
SPISettings(uint32_t clock, BitOrder bitOrder, uint8_t dataMode) {}
};

class SPIClass
{
public:
uint8_t transfer(uint8_t data) { return 0; }
uint16_t transfer16(uint16_t data) { return 0; }
void transfer(void *buf, size_t count) {}

void transfer(const void *txbuf, void *rxbuf, size_t count) {}

void usingInterrupt(int interruptNumber) {}
void notUsingInterrupt(int interruptNumber) {}
void beginTransaction(SPISettings settings) {}
void endTransaction(void) {}

void attachInterrupt() {}
void detachInterrupt() {}

void begin() {}
void end() {}
};

SPIClass SPI;


#endif
39 changes: 39 additions & 0 deletions test/mocks/Wire/Wire.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#ifndef Wire_h
#define Wire_h

#include "Stream.h"

class TwoWire : public Stream
{
public:
TwoWire(uint8_t bus_num){};
~TwoWire(){};
bool setPins(int sda, int scl){};
bool begin(){return true;}
bool begin(uint8_t addr){return true;}
void beginTransmission(uint16_t address){}
void beginTransmission(uint8_t address){}
void beginTransmission(int address){}
uint8_t endTransmission(bool sendStop) { return 0; }
uint8_t endTransmission(void) { return 0; }
size_t requestFrom(uint16_t address, size_t size, bool sendStop) { return 0; }
uint8_t requestFrom(uint16_t address, uint8_t size, bool sendStop) { return 0; }
uint8_t requestFrom(uint16_t address, uint8_t size, uint8_t sendStop) { return 0; }
size_t requestFrom(uint8_t address, size_t len, bool stopBit) { return 0; }
uint8_t requestFrom(uint16_t address, uint8_t size) { return 0; }
uint8_t requestFrom(uint8_t address, uint8_t size, uint8_t sendStop) { return 0; }
uint8_t requestFrom(uint8_t address, uint8_t size) { return 0; }
uint8_t requestFrom(int address, int size, int sendStop) { return 0; }
size_t write(uint8_t) { return 1; }
size_t write(const uint8_t *b, size_t n) { return n; }
int available(){ return 0; }
int read(void) { return 0; }
int peek(void) { return 0; }
bool end(){};
};

extern TwoWire Wire;
extern TwoWire Wire1;

#endif

8 changes: 8 additions & 0 deletions test/test_common/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Common tests

This directory holds tests that are expected to pass on all platforms,
including native and on-device tests.

Tests that exercise device-specific features should should not go here,
and should be capable of passing with hardware features mocked out
(e.g. SPI or Wire are present but return fake responses.)
Loading