mirror of
https://github.com/MarekZegare4/MeshCore-Solo.git
synced 2026-09-26 04:36:40 +00:00
* added unit tests for ConfigSerializer
This commit is contained in:
@@ -167,5 +167,6 @@ build_src_filter =
|
|||||||
-<*>
|
-<*>
|
||||||
+<../src/Utils.cpp>
|
+<../src/Utils.cpp>
|
||||||
+<../src/Packet.cpp>
|
+<../src/Packet.cpp>
|
||||||
|
+<../src/helpers/ConfigSerializer.cpp>
|
||||||
lib_deps =
|
lib_deps =
|
||||||
google/googletest @ 1.17.0
|
google/googletest @ 1.17.0
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ bool ConfigSerializer::loadSerial(Stream& s) {
|
|||||||
if (sp < CONFIG_MAX_DEPTH - 1) {
|
if (sp < CONFIG_MAX_DEPTH - 1) {
|
||||||
sp++;
|
sp++;
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("Error: max nesting reached"); // TODO: debug logging
|
//Serial.printf("Error: max nesting reached"); // TODO: debug logging
|
||||||
context.success = false;
|
context.success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -119,7 +119,7 @@ bool ConfigSerializer::loadSerial(Stream& s) {
|
|||||||
if (sp > 0) {
|
if (sp > 0) {
|
||||||
sp--;
|
sp--;
|
||||||
} else {
|
} else {
|
||||||
Serial.printf("Error: too many closing '}'"); // TODO: debug logging
|
//Serial.printf("Error: too many closing '}'"); // TODO: debug logging
|
||||||
context.success = false;
|
context.success = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <Stream.h>
|
||||||
+64
-3
@@ -1,10 +1,71 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
// Mock Stream class for native testing
|
// Mock Stream class for native testing
|
||||||
// Provides minimal interface needed by Utils.h
|
// Provides minimal interface needed by Utils.h
|
||||||
|
|
||||||
class Stream {
|
#define DEC 10
|
||||||
|
#define HEX 16
|
||||||
|
#define OCT 8
|
||||||
|
#define BIN 2
|
||||||
|
|
||||||
|
class Print
|
||||||
|
{
|
||||||
public:
|
public:
|
||||||
virtual void print(char c) {}
|
virtual size_t write(uint8_t b) { return 1; }
|
||||||
virtual void print(const char* str) {}
|
size_t write(const char *str)
|
||||||
|
{
|
||||||
|
if(str == NULL) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return write((const uint8_t *) str, strlen(str));
|
||||||
|
}
|
||||||
|
virtual size_t write(const uint8_t *buffer, size_t size) {
|
||||||
|
size_t t = 0;
|
||||||
|
for (int i = 0; i < size; i++) { t += write(buffer[i]); }
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
size_t write(const char *buffer, size_t size)
|
||||||
|
{
|
||||||
|
return write((const uint8_t *) buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual size_t print(unsigned char b, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(int v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(unsigned int v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(long v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(unsigned long v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(long long v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(unsigned long long v, int r = DEC) { return 0; }
|
||||||
|
virtual size_t print(double v, int p = 2) { return 0; }
|
||||||
|
|
||||||
|
size_t print(char c) { return write(c); }
|
||||||
|
size_t print(const char* str) { return write(str); }
|
||||||
|
|
||||||
|
//size_t println(void) { return 0; }
|
||||||
|
|
||||||
|
virtual void flush() { /* Empty implementation for backward compatibility */ }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Stream: public Print
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual int available() { return 0; }
|
||||||
|
virtual int read() { return -1; }
|
||||||
|
virtual int peek() { return 0; }
|
||||||
|
|
||||||
|
virtual size_t readBytes(char *buffer, size_t length) {
|
||||||
|
size_t i = 0;
|
||||||
|
while (i < length && available()) {
|
||||||
|
buffer[i++] = read();
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
virtual size_t readBytes(uint8_t *buffer, size_t length)
|
||||||
|
{
|
||||||
|
return readBytes((char *) buffer, length);
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "helpers/ConfigSerializer.h"
|
||||||
|
|
||||||
|
#define TEST_INT_S "56"
|
||||||
|
#define TEST_INT 56
|
||||||
|
#define TEST_FLOAT_S "-6.123"
|
||||||
|
#define TEST_FLOAT -6.1230f
|
||||||
|
#define TEST_DOUBLE_S "12.123456"
|
||||||
|
#define TEST_DOUBLE 12.123456
|
||||||
|
|
||||||
|
class MockInputStream : public Stream {
|
||||||
|
const char* _text;
|
||||||
|
int pos, len;
|
||||||
|
public:
|
||||||
|
MockInputStream(const char* text) : _text(text) { pos = 0; len = strlen(text); }
|
||||||
|
int available() override { return len - pos; }
|
||||||
|
int read() override { if (pos < len) { return _text[pos++]; } return -1; }
|
||||||
|
int peek() override { if (pos < len) { return _text[pos]; } return -1; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockPrintStream : public Stream {
|
||||||
|
int len = 0;
|
||||||
|
uint8_t _buf[1024];
|
||||||
|
public:
|
||||||
|
size_t write(uint8_t b) override {
|
||||||
|
if (len < sizeof(_buf)) {
|
||||||
|
_buf[len++] = b;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t print(unsigned char b, int r) override { if (b == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(int v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(unsigned int v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(long v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(unsigned long v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(long long v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(unsigned long long v, int r) override { if (v == TEST_INT) return Print::print(TEST_INT_S); return 0; }
|
||||||
|
size_t print(double v, int p = 2) override {
|
||||||
|
if (p == 6) return Print::print(TEST_DOUBLE_S);
|
||||||
|
if (p == 4) return Print::print(TEST_FLOAT_S);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getLength() const { return len; }
|
||||||
|
const uint8_t* getBytes() const { return _buf; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class TestStruct : public ConfigSerializer {
|
||||||
|
protected:
|
||||||
|
void structure() override {
|
||||||
|
def("age", age);
|
||||||
|
def("flags", flags);
|
||||||
|
def("name", name, sizeof(name));
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
int32_t age;
|
||||||
|
char name[16];
|
||||||
|
uint8_t flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ── saveSerial: basic ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(ConfigSerializer, SaveSerial_Basic) {
|
||||||
|
MockPrintStream s;
|
||||||
|
TestStruct data;
|
||||||
|
|
||||||
|
data.age = TEST_INT;
|
||||||
|
data.flags = TEST_INT;
|
||||||
|
strcpy(data.name, "Scott");
|
||||||
|
|
||||||
|
bool success = data.saveSerial(s);
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
|
||||||
|
auto l = s.getLength();
|
||||||
|
const char* expect = "{age:" TEST_INT_S ",flags:" TEST_INT_S ",name:\"Scott\"}";
|
||||||
|
EXPECT_EQ(strlen(expect), l);
|
||||||
|
|
||||||
|
bool match = memcmp(s.getBytes(), expect, l) == 0;
|
||||||
|
EXPECT_TRUE(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ── loadSerial: basic ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
TEST(ConfigSerializer, LoadSerial_Basic) {
|
||||||
|
MockInputStream s("{age:" TEST_INT_S ",flags:" TEST_INT_S ",name:\"Scott\"}");
|
||||||
|
TestStruct data;
|
||||||
|
|
||||||
|
bool success = data.loadSerial(s);
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
|
||||||
|
EXPECT_EQ(TEST_INT, data.age);
|
||||||
|
EXPECT_EQ(TEST_INT, data.flags);
|
||||||
|
bool match = strcmp("Scott", data.name) == 0;
|
||||||
|
EXPECT_TRUE(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConfigSerializer, LoadSerial_UnmatchedBraces) {
|
||||||
|
MockInputStream s("{age:" TEST_INT_S ",flags:" TEST_INT_S ",name:\"Scott\"");
|
||||||
|
TestStruct data;
|
||||||
|
|
||||||
|
bool success = data.loadSerial(s);
|
||||||
|
EXPECT_FALSE(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConfigSerializer, LoadSerial_MissingCommas) {
|
||||||
|
MockInputStream s("{age:" TEST_INT_S " flags:" TEST_INT_S " name:\"Scott\"}");
|
||||||
|
TestStruct data;
|
||||||
|
|
||||||
|
bool success = data.loadSerial(s);
|
||||||
|
EXPECT_FALSE(success);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(ConfigSerializer, LoadSerial_IgnoreUnknowns) {
|
||||||
|
MockInputStream s("{age:" TEST_INT_S ",xxx:" TEST_INT_S ",name:\"Scott\"}");
|
||||||
|
TestStruct data;
|
||||||
|
data.flags = 1;
|
||||||
|
|
||||||
|
// should ignore the 'xxx' property
|
||||||
|
bool success = data.loadSerial(s);
|
||||||
|
EXPECT_TRUE(success);
|
||||||
|
|
||||||
|
EXPECT_EQ(TEST_INT, data.age);
|
||||||
|
EXPECT_EQ(1, data.flags); // flags should be unmodified
|
||||||
|
bool match = strcmp("Scott", data.name) == 0;
|
||||||
|
EXPECT_TRUE(match);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ── main ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user