This commit is contained in:
Stephan Mühl
2023-03-22 12:15:18 +01:00
committed by GitHub
parent 3e12414a87
commit adb5102869
203 changed files with 35010 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
#ifndef AHA_AUNITHELPERS_H
#define AHA_AUNITHELPERS_H
#ifdef ARDUINOHA_TEST
#ifdef AUNITER
#include <Arduino.h>
#if defined(__AVR__)
#include <MemoryUsage.h>
#endif
#endif
#define initMqttTest(testDeviceId) \
PubSubClientMock* mock = new PubSubClientMock(); \
HADevice device(testDeviceId); \
HAMqtt mqtt(mock, device); \
mqtt.setDataPrefix("testData"); \
mqtt.begin("testHost", "testUser", "testPass");
#define assertNoMqttMessage() \
assertTrue(mock->getFlushedMessagesNb() == 0);
#define assertMqttMessage(index, eTopic, eMessage, eRetained) { \
const __FlashStringHelper* messageP = F(eMessage); \
size_t messageLen = strlen_P(reinterpret_cast<const char *>(messageP)); \
assertTrue(mock->getFlushedMessagesNb() > 0); \
assertTrue(mock->getFlushedMessagesNb() > index); \
MqttMessage* publishedMessage = mock->getFlushedMessages()[index]; \
assertEqual(eTopic, publishedMessage->topic); \
assertEqual(messageP, publishedMessage->buffer); \
assertEqual(messageLen, publishedMessage->bufferSize - 1); \
assertEqual(eRetained, publishedMessage->retained); \
}
#define assertSingleMqttMessage(eTopic, eMessage, eRetained) { \
assertEqual(1, mock->getFlushedMessagesNb()); \
assertMqttMessage(0, eTopic, eMessage, eRetained) \
}
#define assertEntityConfig(mock, entity, expectedJson) \
{ \
mqtt.loop(); \
assertMqttMessage(0, AHATOFSTR(ConfigTopic), expectedJson, true) \
assertTrue(entity.getSerializer() == nullptr); \
}
#define assertEntityConfigOnTopic(mock, entity, topic, expectedJson) \
{ \
mqtt.loop(); \
assertMqttMessage(0, topic, expectedJson, true) \
assertTrue(entity.getSerializer() == nullptr); \
}
#ifdef AUNITER
#if defined(__AVR__)
#define AHA_FREERAM mu_freeRam()
#elif defined(ESP8266) || defined(ESP32)
#define AHA_FREERAM ESP.getFreeHeap()
#else
#define AHA_FREERAM 0
#endif
#define AHA_LEAKTRACKSTART \
int freeRam = AHA_FREERAM;
#define AHA_LEAKTRACKEND \
int diff = freeRam - AHA_FREERAM; \
if (diff < 0) { diff *= -1; } \
if (diff != 0) { \
Serial.print(Test::getName().getFString()); \
Serial.print(F(" memory leak: ")); \
Serial.print(diff); \
Serial.println(F("b")); \
Test::fail(); \
}
#else
// EpoxyDuino doesn't support memory tracking
#define AHA_LEAKTRACKSTART
#define AHA_LEAKTRACKEND
#endif
#define AHA_TEST(suiteName, name) \
class suiteName##_##name : public aunit::TestOnce { \
public: \
suiteName##_##name(); \
void once() override; \
void loop() override { \
AHA_LEAKTRACKSTART \
once(); \
if (isNotDone()) { pass(); } \
AHA_LEAKTRACKEND \
} \
} suiteName##_##name##_instance; \
suiteName##_##name :: suiteName##_##name() { \
init(AUNIT_F(#suiteName "_" #name)); \
} \
void suiteName##_##name :: once()
#endif
#endif

View File

@@ -0,0 +1,268 @@
#include "PubSubClientMock.h"
#ifdef ARDUINOHA_TEST
#include "../ArduinoHADefines.h"
PubSubClientMock::PubSubClientMock() :
_pendingMessage(nullptr),
_flushedMessages(nullptr),
_flushedMessagesNb(0),
_subscriptions(nullptr),
_subscriptionsNb(0),
callback(nullptr)
{
}
PubSubClientMock::~PubSubClientMock()
{
if (_pendingMessage) {
delete _pendingMessage;
}
clearFlushedMessages();
clearSubscriptions();
}
bool PubSubClientMock::loop()
{
return connected();
}
void PubSubClientMock::disconnect()
{
_connection.connected = false;
}
bool PubSubClientMock::connected()
{
return _connection.connected;
}
bool PubSubClientMock::connect(
const char *id,
const char *user,
const char *pass,
const char* willTopic,
uint8_t willQos,
bool willRetain,
const char* willMessage,
bool cleanSession
)
{
(void)willQos;
(void)cleanSession;
_connection.connected = true;
_connection.id = id;
_connection.user = user;
_connection.pass = pass;
_lastWill.topic = willTopic;
_lastWill.message = willMessage;
_lastWill.retain = willRetain;
return true;
}
bool PubSubClientMock::connectDummy()
{
_connection.connected = true;
_connection.id = "dummyId";
_connection.user = nullptr;
_connection.pass = nullptr;
_lastWill.topic = nullptr;
_lastWill.message = nullptr;
_lastWill.retain = false;
return true;
}
PubSubClientMock& PubSubClientMock::setServer(IPAddress ip, uint16_t port)
{
_connection.ip = ip;
_connection.port = port;
return *this;
}
PubSubClientMock& PubSubClientMock::setServer(
const char * domain,
uint16_t port
)
{
_connection.domain = domain;
_connection.port = port;
return *this;
}
PubSubClientMock& PubSubClientMock::setCallback(MQTT_CALLBACK_SIGNATURE)
{
this->callback = callback;
return *this;
}
bool PubSubClientMock::beginPublish(
const char* topic,
unsigned int plength,
bool retained
)
{
if (!connected()) {
return false;
}
if (_pendingMessage) {
delete _pendingMessage;
}
_pendingMessage = new MqttMessage();
_pendingMessage->retained = retained;
{
size_t size = strlen(topic) + 1;
_pendingMessage->topic = new char[size];
_pendingMessage->topicSize = size;
memset(_pendingMessage->topic, 0, size);
memcpy(_pendingMessage->topic, topic, size);
}
{
size_t size = plength + 1;
_pendingMessage->buffer = new char[size];
_pendingMessage->bufferSize = size;
memset(_pendingMessage->buffer, 0, size);
}
return true;
}
size_t PubSubClientMock::write(const uint8_t *buffer, size_t size)
{
if (!_pendingMessage || !_pendingMessage->buffer) {
return 0;
}
strncat(_pendingMessage->buffer, (const char*)buffer, size);
return size;
}
size_t PubSubClientMock::print(const __FlashStringHelper* buffer)
{
const size_t len = strlen_P(reinterpret_cast<const char*>(buffer));
char data[len + 1]; // including null terminator
strcpy_P(data, reinterpret_cast<const char*>(buffer));
return write((const uint8_t*)(data), len);
}
int PubSubClientMock::endPublish()
{
if (!_pendingMessage) {
return 0;
}
size_t messageSize = _pendingMessage->bufferSize;
uint8_t index = _flushedMessagesNb;
_flushedMessagesNb++;
_flushedMessages = static_cast<MqttMessage**>(
realloc(_flushedMessages, _flushedMessagesNb * sizeof(MqttMessage*))
);
_flushedMessages[index] = _pendingMessage; // handover memory responsibility
_pendingMessage = nullptr; // do not call destructor
return messageSize;
}
bool PubSubClientMock::subscribe(const char* topic)
{
uint8_t index = _subscriptionsNb;
_subscriptionsNb++;
_subscriptions = static_cast<MqttSubscription**>(
realloc(_subscriptions, _subscriptionsNb * sizeof(MqttSubscription*))
);
size_t topicSize = strlen(topic) + 1;
MqttSubscription* subscription = new MqttSubscription();
subscription->topic = new char[topicSize];
memcpy(subscription->topic, topic, topicSize);
_subscriptions[index] = subscription;
return true;
}
void PubSubClientMock::clearFlushedMessages()
{
if (_flushedMessages) {
for (uint8_t i = 0; i < _flushedMessagesNb; i++) {
delete _flushedMessages[i];
}
delete _flushedMessages;
}
_flushedMessagesNb = 0;
}
void PubSubClientMock::clearSubscriptions()
{
if (_subscriptions) {
for (uint8_t i = 0; i < _subscriptionsNb; i++) {
delete _subscriptions[i];
}
delete _subscriptions;
}
_subscriptionsNb = 0;
}
void PubSubClientMock::fakeMessage(const char* topic, const char* message)
{
if (!callback) {
return;
}
uint16_t len = strlen(message);
uint8_t data[len];
memcpy(data, message, len);
callback(const_cast<char*>(topic), data, len);
}
void PubSubClientMock::fakeMessage(
const __FlashStringHelper* topic,
const char* message
)
{
char topicStr[strlen_P(AHAFROMFSTR(topic)) + 1];
topicStr[0] = 0;
strcpy_P(topicStr, AHAFROMFSTR(topic));
fakeMessage(topicStr, message);
}
void PubSubClientMock::fakeMessage(
const __FlashStringHelper* topic,
const __FlashStringHelper* message
)
{
char topicStr[strlen_P(AHAFROMFSTR(topic)) + 1];
topicStr[0] = 0;
strcpy_P(topicStr, AHAFROMFSTR(topic));
char messageStr[strlen_P(AHAFROMFSTR(message)) + 1];
messageStr[0] = 0;
strcpy_P(messageStr, AHAFROMFSTR(message));
fakeMessage(topicStr, messageStr);
}
#endif

View File

@@ -0,0 +1,166 @@
#ifndef AHA_PUBSUBCLIENTMOCK_H
#define AHA_PUBSUBCLIENTMOCK_H
#ifdef ARDUINOHA_TEST
#include <Arduino.h>
#include <IPAddress.h>
#if defined(ESP8266) || defined(ESP32)
#include <functional>
#define MQTT_CALLBACK_SIGNATURE std::function<void(char*, uint8_t*, unsigned int)> callback
#else
#define MQTT_CALLBACK_SIGNATURE void (*callback)(char*, uint8_t*, unsigned int)
#endif
struct MqttMessage
{
char* topic;
size_t topicSize;
char* buffer;
size_t bufferSize;
bool retained;
MqttMessage() :
topic(nullptr),
topicSize(0),
buffer(nullptr),
bufferSize(0),
retained(false)
{
}
~MqttMessage()
{
if (topic) {
delete topic;
}
if (buffer) {
delete buffer;
}
}
};
struct MqttSubscription {
char* topic;
MqttSubscription() :
topic(nullptr)
{
}
~MqttSubscription()
{
if (topic) {
delete topic;
}
}
};
struct MqttConnection
{
bool connected;
const char* domain;
IPAddress ip;
uint16_t port;
const char* id;
const char* user;
const char* pass;
MqttConnection() :
connected(false),
domain(nullptr),
port(0),
id(nullptr),
user(nullptr),
pass(nullptr)
{
}
};
struct MqttWill
{
const char* topic;
const char* message;
bool retain;
MqttWill() :
topic(nullptr),
message(nullptr),
retain(false)
{
}
};
class PubSubClientMock
{
public:
PubSubClientMock();
~PubSubClientMock();
bool loop();
void disconnect();
bool connected();
bool connect(
const char *id,
const char *user,
const char *pass,
const char* willTopic,
uint8_t willQos,
bool willRetain,
const char* willMessage,
bool cleanSession
);
bool connectDummy();
PubSubClientMock& setServer(IPAddress ip, uint16_t port);
PubSubClientMock& setServer(const char* domain, uint16_t port);
PubSubClientMock& setCallback(MQTT_CALLBACK_SIGNATURE);
bool beginPublish(const char* topic, unsigned int plength, bool retained);
size_t write(const uint8_t *buffer, size_t size);
size_t print(const __FlashStringHelper* buffer);
int endPublish();
bool subscribe(const char* topic);
inline uint8_t getFlushedMessagesNb() const
{ return _flushedMessagesNb; }
inline MqttMessage** getFlushedMessages() const
{ return _flushedMessages; }
inline uint8_t getSubscriptionsNb() const
{ return _subscriptionsNb; }
inline MqttSubscription** getSubscriptions() const
{ return _subscriptions; }
inline const MqttConnection& getConnection() const
{ return _connection; }
inline const MqttWill& getLastWill() const
{ return _lastWill; }
void clearFlushedMessages();
void clearSubscriptions();
void fakeMessage(const char* topic, const char* message);
void fakeMessage(const __FlashStringHelper* topic, const char* message);
void fakeMessage(const __FlashStringHelper* topic, const __FlashStringHelper* message);
private:
MqttMessage* _pendingMessage;
MqttMessage** _flushedMessages;
uint8_t _flushedMessagesNb;
MqttSubscription** _subscriptions;
uint8_t _subscriptionsNb;
MqttConnection _connection;
MqttWill _lastWill;
MQTT_CALLBACK_SIGNATURE;
};
#endif
#endif