Native test suite (61 tests, 5 suites) with thin mock layer for Arduino/FreeRTOS/esp_timer enabling host-side testing without hardware. ASCOM Alpaca REST API on port 32323 with UDP discovery, implementing Telescope v3 interface for N.I.N.A., PHD2, and compatible software. Follows existing ST4WiFi conditional compilation pattern. README documents wiring, all three protocols (serial, WebSocket, Alpaca), pin/rate configuration, and build instructions.
186 lines
5.8 KiB
C++
186 lines
5.8 KiB
C++
// ST4Serial unit tests
|
|
#include <unity.h>
|
|
#include "mock_state.h"
|
|
#include "ST4Controller.h"
|
|
#include "ST4Serial.h"
|
|
|
|
static ST4Controller* ctrl;
|
|
static ST4Serial* serial;
|
|
|
|
void setUp() {
|
|
MockState::reset();
|
|
ctrl = new ST4Controller();
|
|
ctrl->begin();
|
|
serial = new ST4Serial();
|
|
serial->begin(*ctrl, Serial, true);
|
|
// Clear the INITIALIZED# output from begin()
|
|
MockState::serialOutput.clear();
|
|
}
|
|
|
|
void tearDown() {
|
|
delete serial;
|
|
delete ctrl;
|
|
serial = nullptr;
|
|
ctrl = nullptr;
|
|
}
|
|
|
|
// Helper: send a command string and process it
|
|
static void sendCommand(const char* cmd) {
|
|
MockState::setSerialInput(cmd);
|
|
Serial.resetReadPos();
|
|
serial->update();
|
|
}
|
|
|
|
void test_connect_command() {
|
|
sendCommand("CONNECT#");
|
|
TEST_ASSERT_TRUE(ctrl->isConnected());
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_disconnect_command() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("DISCONNECT#");
|
|
TEST_ASSERT_FALSE(ctrl->isConnected());
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_ra_plus() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("RA+#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::PLUS, ctrl->axisDirection(ST4AxisId::RA));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_ra_minus() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("RA-#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::MINUS, ctrl->axisDirection(ST4AxisId::RA));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_ra_stop() {
|
|
sendCommand("CONNECT#");
|
|
sendCommand("RA+#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("RA0#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::STOP, ctrl->axisDirection(ST4AxisId::RA));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_dec_plus() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("DEC+#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::PLUS, ctrl->axisDirection(ST4AxisId::DECLINATION));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_dec_minus() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("DEC-#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::MINUS, ctrl->axisDirection(ST4AxisId::DECLINATION));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_dec_stop() {
|
|
sendCommand("CONNECT#");
|
|
sendCommand("DEC+#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("DEC0#");
|
|
TEST_ASSERT_EQUAL(ST4Direction::STOP, ctrl->axisDirection(ST4AxisId::DECLINATION));
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_pulse_command() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("PULSE RA+ 500#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
}
|
|
|
|
void test_pos_query() {
|
|
sendCommand("CONNECT#");
|
|
ctrl->sync(12.345, 45.678);
|
|
MockState::serialOutput.clear();
|
|
sendCommand("POS?#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("POS"));
|
|
}
|
|
|
|
void test_sync_command() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("SYNC 12.345 45.678#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("OK#"));
|
|
TEST_ASSERT_DOUBLE_WITHIN(1e-3, 12.345, ctrl->position(ST4AxisId::RA));
|
|
TEST_ASSERT_DOUBLE_WITHIN(1e-3, 45.678, ctrl->position(ST4AxisId::DECLINATION));
|
|
}
|
|
|
|
void test_status_query() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("STATUS?#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("STATUS"));
|
|
}
|
|
|
|
void test_version_query() {
|
|
MockState::serialOutput.clear();
|
|
sendCommand("VERSION?#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos,
|
|
MockState::serialOutput.find(ST4Constants::VERSION));
|
|
}
|
|
|
|
void test_buffer_overflow() {
|
|
// Send >64 chars then '#' -- should discard the truncated command without crashing
|
|
std::string overflow(70, 'A');
|
|
overflow += '#';
|
|
sendCommand(overflow.c_str());
|
|
// No crash is the pass condition. Output should not contain "OK#" for this garbage
|
|
// (the overflow flag causes discard, so processCommand is never called)
|
|
}
|
|
|
|
void test_sync_garbage_rejected() {
|
|
sendCommand("CONNECT#");
|
|
MockState::serialOutput.clear();
|
|
sendCommand("SYNC garbage data#");
|
|
TEST_ASSERT_NOT_EQUAL(std::string::npos, MockState::serialOutput.find("ERR:INVALID_COORDS#"));
|
|
}
|
|
|
|
void test_partial_buffering() {
|
|
// Send "CON" then "NECT#" across two update() calls
|
|
MockState::setSerialInput("CON");
|
|
Serial.resetReadPos();
|
|
serial->update();
|
|
// No command processed yet
|
|
TEST_ASSERT_FALSE(ctrl->isConnected());
|
|
|
|
MockState::setSerialInput("NECT#");
|
|
Serial.resetReadPos();
|
|
serial->update();
|
|
TEST_ASSERT_TRUE(ctrl->isConnected());
|
|
}
|
|
|
|
int main() {
|
|
UNITY_BEGIN();
|
|
RUN_TEST(test_connect_command);
|
|
RUN_TEST(test_disconnect_command);
|
|
RUN_TEST(test_ra_plus);
|
|
RUN_TEST(test_ra_minus);
|
|
RUN_TEST(test_ra_stop);
|
|
RUN_TEST(test_dec_plus);
|
|
RUN_TEST(test_dec_minus);
|
|
RUN_TEST(test_dec_stop);
|
|
RUN_TEST(test_pulse_command);
|
|
RUN_TEST(test_pos_query);
|
|
RUN_TEST(test_sync_command);
|
|
RUN_TEST(test_status_query);
|
|
RUN_TEST(test_version_query);
|
|
RUN_TEST(test_buffer_overflow);
|
|
RUN_TEST(test_sync_garbage_rejected);
|
|
RUN_TEST(test_partial_buffering);
|
|
return UNITY_END();
|
|
}
|