diff --git a/.github/workflows/manual-flash.yaml b/.github/workflows/manual-flash.yaml index 0bba37e..aec95ac 100644 --- a/.github/workflows/manual-flash.yaml +++ b/.github/workflows/manual-flash.yaml @@ -41,7 +41,7 @@ jobs: - name: Download latest firmware artifact if: github.event.inputs.use_latest_artifact == 'yes' - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: workflow: manual-compile.yaml name: firmware-binary diff --git a/.github/workflows/manual-upload.yaml b/.github/workflows/manual-upload.yaml index 7b69dc6..d308cd1 100644 --- a/.github/workflows/manual-upload.yaml +++ b/.github/workflows/manual-upload.yaml @@ -45,7 +45,7 @@ jobs: - name: Download release artifacts if: github.event.inputs.use_release_artifact == 'yes' - uses: dawidd6/action-download-artifact@v3 + uses: dawidd6/action-download-artifact@v6 with: workflow: manual-release.yaml name: release-artifacts diff --git a/.github/workflows/pr-workflow.yaml b/.github/workflows/pr-workflow.yaml index eef8465..6b83b0b 100644 --- a/.github/workflows/pr-workflow.yaml +++ b/.github/workflows/pr-workflow.yaml @@ -3,7 +3,7 @@ name: Pull Request Workflow on: # Runs on PR open pull_request: - types: [opened, reopened, synchronize] + types: [opened, reopened, synchronize, edited] branches: - master # or 'main' depending on your main branch diff --git a/.gitmodules b/.gitmodules index fc0685c..9931ca3 100644 --- a/.gitmodules +++ b/.gitmodules @@ -131,3 +131,9 @@ [submodule "test/external/fff"] path = test/external/fff url = https://github.com/meekrosoft/fff.git +[submodule "lib/FlightControl-platform-dependencies"] + path = lib/FlightControl-platform-dependencies + url = https://github.com/gemsiot/FlightControl-platform-dependencies +[submodule "lib/FlightControl-hardware-dependencies"] + path = lib/FlightControl-hardware-dependencies + url = https://github.com/gemsiot/FlightControl-hardware-dependencies diff --git a/CMakeLists.txt b/CMakeLists.txt index 6e61118..bd21d6a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.14) project(FlightControl_Demo_Tests) # Specify C++ standard -set(CMAKE_CXX_STANDARD 14) +set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Add test directory diff --git a/lib/Driver_-_Li710 b/lib/Driver_-_Li710 index c43b276..d5616c6 160000 --- a/lib/Driver_-_Li710 +++ b/lib/Driver_-_Li710 @@ -1 +1 @@ -Subproject commit c43b276337d09504a9f53c28270dee2190e31ea1 +Subproject commit d5616c60261d93517faf6d8b580ec932b9185ef2 diff --git a/lib/Driver_-_Sensor b/lib/Driver_-_Sensor index d13c2ac..afef963 160000 --- a/lib/Driver_-_Sensor +++ b/lib/Driver_-_Sensor @@ -1 +1 @@ -Subproject commit d13c2ac5771b446bc8010937e9218b6a80fe0ff7 +Subproject commit afef96338232e397656a907ce12338a4c9cad288 diff --git a/lib/Driver_-_Talon-SDI12 b/lib/Driver_-_Talon-SDI12 index c97deae..6439b28 160000 --- a/lib/Driver_-_Talon-SDI12 +++ b/lib/Driver_-_Talon-SDI12 @@ -1 +1 @@ -Subproject commit c97deaeacbc7db7784d9c5dde4189687f114364a +Subproject commit 6439b287dd1513858b8f8449e5250ac166215456 diff --git a/lib/FlightControl-hardware-dependencies b/lib/FlightControl-hardware-dependencies new file mode 160000 index 0000000..1fec360 --- /dev/null +++ b/lib/FlightControl-hardware-dependencies @@ -0,0 +1 @@ +Subproject commit 1fec36002d6e53980f6091d81b1e466944b55345 diff --git a/lib/FlightControl-platform-dependencies b/lib/FlightControl-platform-dependencies new file mode 160000 index 0000000..183167f --- /dev/null +++ b/lib/FlightControl-platform-dependencies @@ -0,0 +1 @@ +Subproject commit 183167f55afbe499f67b8ad22292a9c12602bdc6 diff --git a/src/FlightControl_Demo.cpp b/src/FlightControl_Demo.cpp index 377d772..fd9af8b 100644 --- a/src/FlightControl_Demo.cpp +++ b/src/FlightControl_Demo.cpp @@ -59,6 +59,9 @@ int configurePowerSave(int desiredPowerSaveMode); #include #include +#include "hardware/SDI12TalonAdapter.h" +#include "platform/ParticleTimeProvider.h" + const String firmwareVersion = "2.9.11"; const String schemaVersion = "2.2.9"; @@ -75,6 +78,8 @@ I2CTalon i2c(0, 0x21); //Instantiate I2C talon with alt - null port and hardware SDI12Talon sdi12(0, 0x14); //Instantiate SDI12 talon with alt - null port and hardware v1.4 PCAL9535A ioAlpha(0x20); PCAL9535A ioBeta(0x21); +SDI12TalonAdapter realSdi12(sdi12); +ParticleTimeProvider realTimeProvider; String globalNodeID = ""; //Store current node ID @@ -114,7 +119,7 @@ TDR315H soil2(sdi12, 0, 0); //Instantiate soil sensor with default ports and unk TDR315H soil3(sdi12, 0, 0); //Instantiate soil sensor with default ports and unknown version, pass over SDI12 Talon interface Hedorah gas(0, 0, 0x10); //Instantiate CO2 sensor with default ports and v1.0 hardware // T9602 humidity(0, 0, 0x00); //Instantiate Telair T9602 with default ports and version v0.0 -LI710 et(sdi12, 0, 0); //Instantiate ET sensor with default ports and unknown version, pass over SDI12 Talon interface +LI710 et(realTimeProvider, realSdi12, 0, 0); //Instantiate ET sensor with default ports and unknown version, pass over SDI12 Talon interface BaroVue10 campPressure(sdi12, 0, 0x00); // Instantiate Barovue10 with default ports and v0.0 hardware const uint8_t numSensors = 7; //Number must match the number of objects defined in `sensors` array @@ -1077,7 +1082,7 @@ int wakeSensors() for(int s = 0; s < numSensors; s++) { if(sensors[s]->getTalonPort() != 0) { logger.enableData(sensors[s]->getTalonPort(), true); //Turn on data for given port - sensors[s]->wake(); //Wake each sensor + sensors[s]->wake(realTimeProvider); //Wake each sensor logger.enableData(sensors[s]->getTalonPort(), false); //Turn data back off for given port } } diff --git a/src/hardware/SDI12TalonAdapter.h b/src/hardware/SDI12TalonAdapter.h new file mode 100644 index 0000000..70bc2ee --- /dev/null +++ b/src/hardware/SDI12TalonAdapter.h @@ -0,0 +1,54 @@ +// src/hardware/SDI12TalonAdapter.h + +#ifndef SDI12_TALON_ADAPTER_H +#define SDI12_TALON_ADAPTER_H + +#include "ISDI12Talon.h" +#include "SDI12Talon.h" + +/** + * @brief Adapter implementing ISDI12Talon interface + * + * Adapts the concrete SDI12Talon class to the ISDI12Talon interface + * for dependency injection and testing purposes. + */ +class SDI12TalonAdapter : public ISDI12Talon { +public: + /** + * @brief Constructor that takes a reference to a concrete SDI12Talon + * @param talon The concrete SDI12Talon implementation to delegate to + */ + SDI12TalonAdapter(SDI12Talon& talon) : talon(talon) {} + ~SDI12TalonAdapter() override = default; + + // SDI12 communication methods + int getAddress() override { return talon.getAddress(); } + String sendCommand(String command) override { return talon.sendCommand(command); } + String command(String commandStr, int address) override { return talon.command(commandStr, address); } + int startMeasurment(int Address) override { return talon.startMeasurment(Address); } + int startMeasurmentIndex(int index, int Address) override { return talon.startMeasurmentIndex(index, Address); } + String continuousMeasurmentCRC(int Measure, int Address) override { return talon.continuousMeasurmentCRC(Measure, Address); } + bool testCRC(String message) override { return talon.testCRC(message); } + + // Port management methods + int enableData(uint8_t port, bool state) override { return talon.enableData(port, state); } + int enablePower(uint8_t port, bool state) override { return talon.enablePower(port, state); } + void disableDataAll() override { talon.disableDataAll(); } + uint8_t getNumPorts() override { return talon.getNumPorts(); } + + // Sensor interrogation + bool isPresent() override { return talon.isPresent(); } + + // Error handling and state reporting + //int throwError(uint32_t error) override { return talon.throwError(error); } + String getSensorPortString() override { return talon.getSensorPortString(); } + String getTalonPortString() override { return talon.getTalonPortString(); } + uint8_t getSensorPort() override { return talon.getSensorPort(); } + uint8_t getTalonPort() override { return talon.getTalonPort(); } + int restart() override { return talon.restart(); } + +private: + SDI12Talon& talon; // Reference to the concrete implementation +}; + +#endif // SDI12_TALON_ADAPTER_H \ No newline at end of file diff --git a/src/platform/ParticleTimeProvider.cpp b/src/platform/ParticleTimeProvider.cpp new file mode 100644 index 0000000..e27a815 --- /dev/null +++ b/src/platform/ParticleTimeProvider.cpp @@ -0,0 +1,24 @@ +// src/platform/ParticleTimeProvider.cpp +#include "ParticleTimeProvider.h" + +// Use :: prefix for global scope functions like millis() and delay() +// to avoid potential name conflicts if methods had same name. + +int ParticleTimeProvider::year() { return Time.year(); } +int ParticleTimeProvider::year(time_t t) { return Time.year(t); } +int ParticleTimeProvider::month() { return Time.month(); } +int ParticleTimeProvider::month(time_t t) { return Time.month(t); } +int ParticleTimeProvider::day() { return Time.day(); } +int ParticleTimeProvider::day(time_t t) { return Time.day(t); } +int ParticleTimeProvider::hour() { return Time.hour(); } +int ParticleTimeProvider::hour(time_t t) { return Time.hour(t); } +int ParticleTimeProvider::minute() { return Time.minute(); } +int ParticleTimeProvider::minute(time_t t) { return Time.minute(t); } +int ParticleTimeProvider::second() { return Time.second(); } +int ParticleTimeProvider::second(time_t t) { return Time.second(t); } +time_t ParticleTimeProvider::now() { return Time.now(); } +void ParticleTimeProvider::setTime(time_t t) { Time.setTime(t); } +bool ParticleTimeProvider::isValid() { return Time.isValid(); } +void ParticleTimeProvider::zone(float GMT_Offset) { Time.zone(GMT_Offset); } +uint32_t ParticleTimeProvider::millis() { return ::millis(); } +void ParticleTimeProvider::delay(uint32_t ms) { ::delay(ms); } \ No newline at end of file diff --git a/src/platform/ParticleTimeProvider.h b/src/platform/ParticleTimeProvider.h new file mode 100644 index 0000000..3410802 --- /dev/null +++ b/src/platform/ParticleTimeProvider.h @@ -0,0 +1,38 @@ +// src/platform/ParticleTimeProvider.h +#ifndef PARTICLE_TIME_PROVIDER_H +#define PARTICLE_TIME_PROVIDER_H + +#include "ITimeProvider.h" // Include the interface definition +#include "Particle.h" // Include the actual Particle header HERE + +/** + * @brief Concrete implementation of ITimeProvider using Particle API. + */ +class ParticleTimeProvider : public ITimeProvider { +public: + // Constructor/Destructor (often default is fine) + ParticleTimeProvider() = default; + ~ParticleTimeProvider() override = default; + + // Implement methods from ITimeProvider + int year() override; + int year(time_t t) override; + int month() override; + int month(time_t t) override; + int day() override; + int day(time_t t) override; + int hour() override; + int hour(time_t t) override; + int minute() override; + int minute(time_t t) override; + int second() override; + int second(time_t t) override; + time_t now() override; + void setTime(time_t t) override; + bool isValid() override; + void zone(float GMT_Offset) override; + uint32_t millis() override; + void delay(uint32_t ms) override; +}; + +#endif // PARTICLE_TIME_PROVIDER_H \ No newline at end of file diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index af8e3f2..e052d37 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,33 +1,42 @@ # FlightControl_Demo/test/CMakeLists.txt +#allow debugging +set(CMAKE_BUILD_TYPE Debug) + # Add GoogleTest add_subdirectory(external/googletest) # Define the TESTING preprocessor macro for all test builds add_compile_definitions(TESTING) -# IMPORTANT: Make sure mocks are included first to override system headers -include_directories(BEFORE mocks) - -# Include FFF headers -include_directories(external/fff) +# Set C++ standard +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Include Google Test headers +# Include Google Test and Google Mock headers include_directories(external/googletest/googletest/include) +include_directories(external/googletest/googlemock/include) + +# Find all driver directories and add them to the include path +file(GLOB DRIVER_DIRS ${CMAKE_SOURCE_DIR}/lib/*/src) + +# Create a library for the mocks +file(GLOB MOCK_SOURCES + ${CMAKE_CURRENT_SOURCE_DIR}/mocks/*.cpp +) -# Create a mocks library -add_library(mocks STATIC - mocks/MockWire.cpp - mocks/MockArduino.cpp - mocks/MockPCAL9535A.cpp - mocks/MockMCP79412.cpp - mocks/MockSPI.cpp - mocks/MockPCA9634.cpp - mocks/MockSHT4x.cpp - mocks/MockVEML3328.cpp - mocks/MockPAC1934.cpp - mocks/MockMXC6655.cpp - mocks/MockBMA456.cpp - mocks/MockGNSS.cpp +# Add a library of mocks - if there are no source files yet, use an interface library +if(MOCK_SOURCES) + add_library(mocks ${MOCK_SOURCES}) +else() + add_library(mocks INTERFACE) +endif() + +# Add header include directories for mocks - mock directory MUST be first +target_include_directories(mocks BEFORE INTERFACE + ${CMAKE_CURRENT_SOURCE_DIR}/mocks # Mocks FIRST + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/src + ${DRIVER_DIRS} # Add all driver directories ) # Specify test executable @@ -36,27 +45,13 @@ add_executable(unit_tests main.cpp # Kestrel tests - unit/Driver_-_Kestrel/Driver_-_KestrelSetupTests.cpp - unit/Driver_-_Kestrel/Driver_-_KestrelFunctionTests.cpp + #unit/Driver_-_Kestrel/KestrelTest.cpp + #${CMAKE_SOURCE_DIR}/lib/Driver_-_Kestrel/src/Kestrel.cpp + + # Li710 tests + unit/Driver_-_Li710/Li710Test.cpp + ${CMAKE_SOURCE_DIR}/lib/Driver_-_Li710/src/Li710.cpp ) # Link against mocks and GoogleTest -target_link_libraries(unit_tests mocks gtest gtest_main) - -# Find all driver directories and add them to the include path -file(GLOB DRIVER_DIRS ${CMAKE_SOURCE_DIR}/lib/*/src) - -# Add header include directories - mock directory MUST be first -target_include_directories(mocks BEFORE PUBLIC - ${CMAKE_CURRENT_SOURCE_DIR}/mocks # Mocks FIRST - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src - ${DRIVER_DIRS} # Add all driver directories -) - -target_include_directories(unit_tests BEFORE PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/mocks # Mocks FIRST - ${CMAKE_CURRENT_SOURCE_DIR} - ${CMAKE_SOURCE_DIR}/src - ${DRIVER_DIRS} # Add all driver directories -) \ No newline at end of file +target_link_libraries(unit_tests mocks gtest gtest_main gmock) \ No newline at end of file diff --git a/test/main.cpp b/test/main.cpp index ec03b1f..879b780 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,8 +1,5 @@ // FlightControl_Demo/test/main.cpp #include "gtest/gtest.h" -#include "fff.h" - -DEFINE_FFF_GLOBALS; int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); diff --git a/test/mocks/Arduino.h b/test/mocks/Arduino.h deleted file mode 100644 index 371a6c9..0000000 --- a/test/mocks/Arduino.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -// Include our Arduino mocks -#include "MockArduino.h" - -// Arduino standard libraries -#include -#include -#include - -// Forward declarations for common Arduino types and functions -// This will silence most Arduino.h include errors -typedef uint8_t byte; - -class HardwareSerial { -public: - void begin(unsigned long baud) {} - int available() { return 0; } - int read() { return -1; } - void print(const char* str) {} - void print(int val) {} - void println(const char* str) {} - void println(int val) {} -}; - -extern HardwareSerial Serial1; -extern HardwareSerial Serial2; - -// Add more Arduino types/functions as needed \ No newline at end of file diff --git a/test/mocks/MockArduino.cpp b/test/mocks/MockArduino.cpp deleted file mode 100644 index a3ebc20..0000000 --- a/test/mocks/MockArduino.cpp +++ /dev/null @@ -1,31 +0,0 @@ -// test/mocks/MockArduino.cpp -#include "MockArduino.h" - -// Define fake functions -DEFINE_FAKE_VOID_FUNC(pinMode, uint8_t, uint8_t); -DEFINE_FAKE_VOID_FUNC(digitalWrite, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(int, digitalRead, uint8_t); -DEFINE_FAKE_VALUE_FUNC(int, analogRead, uint8_t); -DEFINE_FAKE_VOID_FUNC(analogWrite, uint8_t, int); - -// Time functions -DEFINE_FAKE_VALUE_FUNC(unsigned long, millis); -DEFINE_FAKE_VALUE_FUNC(unsigned long, micros); -DEFINE_FAKE_VOID_FUNC(delay, unsigned long); -DEFINE_FAKE_VOID_FUNC(delayMicroseconds, unsigned int); - -// Misc -DEFINE_FAKE_VOID_FUNC(randomSeed, unsigned long); -DEFINE_FAKE_VALUE_FUNC(long, random, long, long); - -// Serial functions -DEFINE_FAKE_VOID_FUNC(Serial_begin, unsigned long); -DEFINE_FAKE_VALUE_FUNC(int, Serial_available); -DEFINE_FAKE_VALUE_FUNC(int, Serial_read); -DEFINE_FAKE_VOID_FUNC(Serial_print_s, const char*); -DEFINE_FAKE_VOID_FUNC(Serial_print_i, int); -DEFINE_FAKE_VOID_FUNC(Serial_println_s, const char*); -DEFINE_FAKE_VOID_FUNC(Serial_println_i, int); - -// Define the global Serial instance -MockSerial Serial; \ No newline at end of file diff --git a/test/mocks/MockArduino.h b/test/mocks/MockArduino.h deleted file mode 100644 index 4e36f5a..0000000 --- a/test/mocks/MockArduino.h +++ /dev/null @@ -1,89 +0,0 @@ -// test/mocks/MockArduino.h -#pragma once - -#include -#include "fff.h" - -// Define Arduino pin modes -#define INPUT 0 -#define OUTPUT 1 -#define INPUT_PULLUP 2 -#define INPUT_PULLDOWN 3 - -// Define pin values -#define HIGH 1 -#define LOW 0 - -// Define common Arduino pins -#define A0 14 -#define A1 15 -#define A2 16 -#define A3 17 -#define A4 18 -#define A5 19 -#define A6 20 -#define A7 21 -#define D0 0 -#define D1 1 -#define D2 2 -#define D3 3 -#define D4 4 -#define D5 5 -#define D6 6 -#define D7 7 -#define D8 8 -#define D9 9 -#define D10 10 -#define D11 11 -#define D12 12 -#define D13 13 -#define D14 14 -#define D15 15 -#define D16 16 -#define D17 17 -#define D18 18 -#define D19 19 -#define D20 20 -#define D21 21 -#define D22 22 -#define D23 23 - -// Digital and Analog I/O -DECLARE_FAKE_VOID_FUNC(pinMode, uint8_t, uint8_t); -DECLARE_FAKE_VOID_FUNC(digitalWrite, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(int, digitalRead, uint8_t); -DECLARE_FAKE_VALUE_FUNC(int, analogRead, uint8_t); -DECLARE_FAKE_VOID_FUNC(analogWrite, uint8_t, int); - -// Time functions -DECLARE_FAKE_VALUE_FUNC(unsigned long, millis); -DECLARE_FAKE_VALUE_FUNC(unsigned long, micros); -DECLARE_FAKE_VOID_FUNC(delay, unsigned long); -DECLARE_FAKE_VOID_FUNC(delayMicroseconds, unsigned int); - -// Misc -DECLARE_FAKE_VOID_FUNC(randomSeed, unsigned long); -DECLARE_FAKE_VALUE_FUNC(long, random, long, long); - -// Forward declarations for Serial functions -DECLARE_FAKE_VOID_FUNC(Serial_begin, unsigned long); -DECLARE_FAKE_VALUE_FUNC(int, Serial_available); -DECLARE_FAKE_VALUE_FUNC(int, Serial_read); -DECLARE_FAKE_VOID_FUNC(Serial_print_s, const char*); -DECLARE_FAKE_VOID_FUNC(Serial_print_i, int); -DECLARE_FAKE_VOID_FUNC(Serial_println_s, const char*); -DECLARE_FAKE_VOID_FUNC(Serial_println_i, int); - -// Mock class for the Serial object -class MockSerial { -public: - void begin(unsigned long baud) { Serial_begin(baud); } - int available() { return Serial_available(); } - int read() { return Serial_read(); } - void print(const char* str) { Serial_print_s(str); } - void print(int val) { Serial_print_i(val); } - void println(const char* str) { Serial_println_s(str); } - void println(int val) { Serial_println_i(val); } -}; - -extern MockSerial Serial; \ No newline at end of file diff --git a/test/mocks/MockBMA456.cpp b/test/mocks/MockBMA456.cpp deleted file mode 100644 index 66d38e2..0000000 --- a/test/mocks/MockBMA456.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include "MockBMA456.h" - -// Define fake functions for BMA456 -DEFINE_FAKE_VALUE_FUNC(bool, BMA456_begin); -DEFINE_FAKE_VALUE_FUNC(bool, BMA456_readAcceleration, float*, float*, float*); -DEFINE_FAKE_VALUE_FUNC(bool, BMA456_enableStepCounter, bool); -DEFINE_FAKE_VALUE_FUNC(uint32_t, BMA456_getStepCount); -DEFINE_FAKE_VALUE_FUNC(bool, BMA456_resetStepCounter); - -// Initialize the global object -BMA456 accel_bma456; \ No newline at end of file diff --git a/test/mocks/MockBMA456.h b/test/mocks/MockBMA456.h deleted file mode 100644 index 40549fa..0000000 --- a/test/mocks/MockBMA456.h +++ /dev/null @@ -1,37 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions for BMA456 accelerometer -DECLARE_FAKE_VALUE_FUNC(bool, BMA456_begin); -DECLARE_FAKE_VALUE_FUNC(bool, BMA456_readAcceleration, float*, float*, float*); -DECLARE_FAKE_VALUE_FUNC(bool, BMA456_enableStepCounter, bool); -DECLARE_FAKE_VALUE_FUNC(uint32_t, BMA456_getStepCount); -DECLARE_FAKE_VALUE_FUNC(bool, BMA456_resetStepCounter); - -// Mock class for BMA456 via arduino_bma456 -class BMA456 { -public: - // Default mock values - float x_acceleration = 0.0f; - float y_acceleration = 0.0f; - float z_acceleration = 1.0f; // Default to 1G in Z direction (earth gravity) - uint32_t step_count = 0; - - bool begin() { return BMA456_begin(); } - - bool readAcceleration(float* x, float* y, float* z) { - *x = x_acceleration; - *y = y_acceleration; - *z = z_acceleration; - return BMA456_readAcceleration(x, y, z); - } - - bool enableStepCounter(bool enable) { return BMA456_enableStepCounter(enable); } - uint32_t getStepCount() { return BMA456_getStepCount(); } - bool resetStepCounter() { return BMA456_resetStepCounter(); } -}; - -// This simulates the global object provided by the arduino_bma456 library -extern BMA456 accel_bma456; \ No newline at end of file diff --git a/test/mocks/MockGNSS.cpp b/test/mocks/MockGNSS.cpp deleted file mode 100644 index 4d88aa9..0000000 --- a/test/mocks/MockGNSS.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "MockGNSS.h" - -// Define fake functions for GNSS -DEFINE_FAKE_VALUE_FUNC(bool, GNSS_begin, int); -DEFINE_FAKE_VALUE_FUNC(bool, GNSS_isConnected); -DEFINE_FAKE_VALUE_FUNC(bool, GNSS_setI2COutput, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, GNSS_setNavigationFrequency, uint8_t); -DEFINE_FAKE_VALUE_FUNC(long, GNSS_getLatitude); -DEFINE_FAKE_VALUE_FUNC(long, GNSS_getLongitude); -DEFINE_FAKE_VALUE_FUNC(long, GNSS_getAltitude); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getSIV); -DEFINE_FAKE_VALUE_FUNC(uint32_t, GNSS_getTimeOfWeek); -DEFINE_FAKE_VALUE_FUNC(uint16_t, GNSS_getYear); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getMonth); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getDay); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getHour); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getMinute); -DEFINE_FAKE_VALUE_FUNC(uint8_t, GNSS_getSecond); \ No newline at end of file diff --git a/test/mocks/MockGNSS.h b/test/mocks/MockGNSS.h deleted file mode 100644 index 7511d12..0000000 --- a/test/mocks/MockGNSS.h +++ /dev/null @@ -1,58 +0,0 @@ -#pragma once - -#include "fff.h" -#include -#include - -// Declare fake functions for u-blox GNSS -DECLARE_FAKE_VALUE_FUNC(bool, GNSS_begin, int); -DECLARE_FAKE_VALUE_FUNC(bool, GNSS_isConnected); -DECLARE_FAKE_VALUE_FUNC(bool, GNSS_setI2COutput, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, GNSS_setNavigationFrequency, uint8_t); -DECLARE_FAKE_VALUE_FUNC(long, GNSS_getLatitude); -DECLARE_FAKE_VALUE_FUNC(long, GNSS_getLongitude); -DECLARE_FAKE_VALUE_FUNC(long, GNSS_getAltitude); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getSIV); -DECLARE_FAKE_VALUE_FUNC(uint32_t, GNSS_getTimeOfWeek); -DECLARE_FAKE_VALUE_FUNC(uint16_t, GNSS_getYear); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getMonth); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getDay); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getHour); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getMinute); -DECLARE_FAKE_VALUE_FUNC(uint8_t, GNSS_getSecond); - -// Mock class for SFE_UBLOX_GNSS -class SFE_UBLOX_GNSS { -public: - // Default mock values - long latitude = 449673925; // Minneapolis ~44.96°N - long longitude = -932838386; // Minneapolis ~-93.28°E - long altitude = 25000; // 250m above MSL - uint8_t satellites = 8; // 8 satellites in view - - // Time values - uint16_t year = 2023; - uint8_t month = 5; - uint8_t day = 15; - uint8_t hour = 10; - uint8_t minute = 30; - uint8_t second = 0; - - bool begin(int wirePort = 0) { return GNSS_begin(wirePort); } - bool isConnected() { return GNSS_isConnected(); } - bool setI2COutput(uint8_t comSettings) { return GNSS_setI2COutput(comSettings); } - bool setNavigationFrequency(uint8_t navFreq) { return GNSS_setNavigationFrequency(navFreq); } - - long getLatitude() { return GNSS_getLatitude(); } - long getLongitude() { return GNSS_getLongitude(); } - long getAltitude() { return GNSS_getAltitude(); } - uint8_t getSIV() { return GNSS_getSIV(); } - - uint32_t getTimeOfWeek() { return GNSS_getTimeOfWeek(); } - uint16_t getYear() { return GNSS_getYear(); } - uint8_t getMonth() { return GNSS_getMonth(); } - uint8_t getDay() { return GNSS_getDay(); } - uint8_t getHour() { return GNSS_getHour(); } - uint8_t getMinute() { return GNSS_getMinute(); } - uint8_t getSecond() { return GNSS_getSecond(); } -}; \ No newline at end of file diff --git a/test/mocks/MockIncludes.h b/test/mocks/MockIncludes.h deleted file mode 100644 index 0a677c9..0000000 --- a/test/mocks/MockIncludes.h +++ /dev/null @@ -1,65 +0,0 @@ -#pragma once - -// This file contains includes and settings for testing the Kestrel driver with real code -// It ensures we properly redirect hardware calls to mocks while avoiding redefinition errors - -// Tell the compiler we're in testing mode - this can be used in #ifdef blocks -#define TESTING - -// First define all the hardware classes as empty forward declarations -// This prevents the real implementations from being compiled -class Sensor; -class PCAL9535A; -class PCA9634; -class MCP79412; -class SFE_UBLOX_GNSS; -class PAC1934; -class VEML3328; -class Adafruit_SHT4x; -class MXC6655; -class BMA456; - -// Now include our mock implementations -#include "MockSensor.h" -#include "MockPCAL9535A.h" -#include "MockPCA9634.h" -#include "MockMCP79412.h" -#include "MockGNSS.h" -#include "MockPAC1934.h" -#include "MockVEML3328.h" -#include "MockSHT4x.h" -#include "MockMXC6655.h" -#include "MockBMA456.h" -#include "MockArduino.h" -#include "MockWireDeclare.h" - -// Define any constants that might be needed by Kestrel.h -#define OUTPUT 1 -#define INPUT 0 -#define HIGH 1 -#define LOW 0 - -// Arduino constants -#define A0 14 -#define A1 15 -#define A2 16 -#define A3 17 -#define A4 18 -#define A5 19 -#define A6 20 -#define A7 21 -#define D0 0 -#define D1 1 -#define D2 2 -#define D3 3 -#define D4 4 -#define D5 5 -#define D6 6 -#define D7 7 -#define D8 8 -#define D22 22 -#define D23 23 - -// Define additional constants that Kestrel.h might need -// If there are specific enum values or constants that Kestrel.h expects, -// add them here \ No newline at end of file diff --git a/test/mocks/MockMCP79412.cpp b/test/mocks/MockMCP79412.cpp deleted file mode 100644 index 2641e83..0000000 --- a/test/mocks/MockMCP79412.cpp +++ /dev/null @@ -1,13 +0,0 @@ -#include "MockMCP79412.h" - -// Define fake functions -DEFINE_FAKE_VALUE_FUNC(bool, MCP79412_begin); -DEFINE_FAKE_VALUE_FUNC(time_t, MCP79412_getTime); -DEFINE_FAKE_VALUE_FUNC(bool, MCP79412_setTime, time_t); - -// Set default behavior -void setup_mock_MCP79412_defaults() { - MCP79412_begin_fake.return_val = true; - MCP79412_getTime_fake.return_val = time(NULL); // Current time - MCP79412_setTime_fake.return_val = true; -} \ No newline at end of file diff --git a/test/mocks/MockMCP79412.h b/test/mocks/MockMCP79412.h deleted file mode 100644 index b2117ae..0000000 --- a/test/mocks/MockMCP79412.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "fff.h" -#include -#include - -// Declare fake functions -DECLARE_FAKE_VALUE_FUNC(bool, MCP79412_begin); -DECLARE_FAKE_VALUE_FUNC(time_t, MCP79412_getTime); -DECLARE_FAKE_VALUE_FUNC(bool, MCP79412_setTime, time_t); - -// Mock class for MCP79412 RTC -class MCP79412 { -public: - bool begin() { return MCP79412_begin(); } - time_t getTime() { return MCP79412_getTime(); } - bool setTime(time_t time) { return MCP79412_setTime(time); } - - // Additional properties to match the real implementation - uint8_t numErrors = 0; - - // Add more methods as needed for Kestrel tests -}; \ No newline at end of file diff --git a/test/mocks/MockMXC6655.cpp b/test/mocks/MockMXC6655.cpp deleted file mode 100644 index 535b0dc..0000000 --- a/test/mocks/MockMXC6655.cpp +++ /dev/null @@ -1,6 +0,0 @@ -#include "MockMXC6655.h" - -// Define fake functions for MXC6655 -DEFINE_FAKE_VALUE_FUNC(bool, MXC6655_begin); -DEFINE_FAKE_VALUE_FUNC(bool, MXC6655_readAcceleration, float*, float*, float*); -DEFINE_FAKE_VALUE_FUNC(bool, MXC6655_resetOrientation); \ No newline at end of file diff --git a/test/mocks/MockMXC6655.h b/test/mocks/MockMXC6655.h deleted file mode 100644 index 40509ef..0000000 --- a/test/mocks/MockMXC6655.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions for MXC6655 accelerometer -DECLARE_FAKE_VALUE_FUNC(bool, MXC6655_begin); -DECLARE_FAKE_VALUE_FUNC(bool, MXC6655_readAcceleration, float*, float*, float*); -DECLARE_FAKE_VALUE_FUNC(bool, MXC6655_resetOrientation); - -// Mock class for MXC6655 accelerometer -class MXC6655 { -public: - // Default mock values - float x_acceleration = 0.0f; - float y_acceleration = 0.0f; - float z_acceleration = 1.0f; // Default to 1G in Z direction (earth gravity) - - bool begin() { return MXC6655_begin(); } - - bool readAcceleration(float* x, float* y, float* z) { - *x = x_acceleration; - *y = y_acceleration; - *z = z_acceleration; - return MXC6655_readAcceleration(x, y, z); - } - - bool resetOrientation() { return MXC6655_resetOrientation(); } -}; \ No newline at end of file diff --git a/test/mocks/MockPAC1934.cpp b/test/mocks/MockPAC1934.cpp deleted file mode 100644 index a1c86ff..0000000 --- a/test/mocks/MockPAC1934.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "MockPAC1934.h" - -// Define fake functions -DEFINE_FAKE_VALUE_FUNC(bool, PAC1934_begin); -DEFINE_FAKE_VALUE_FUNC(float, PAC1934_readVoltage, uint8_t); -DEFINE_FAKE_VALUE_FUNC(float, PAC1934_readCurrent, uint8_t); -DEFINE_FAKE_VALUE_FUNC(float, PAC1934_readPower, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PAC1934_enableChannel, uint8_t, bool); - -// Set default behavior -void setup_mock_PAC1934_defaults() { - PAC1934_begin_fake.return_val = true; - PAC1934_readVoltage_fake.return_val = 3.3f; - PAC1934_readCurrent_fake.return_val = 0.1f; - PAC1934_readPower_fake.return_val = 0.33f; - PAC1934_enableChannel_fake.return_val = true; -} diff --git a/test/mocks/MockPAC1934.h b/test/mocks/MockPAC1934.h deleted file mode 100644 index b39276f..0000000 --- a/test/mocks/MockPAC1934.h +++ /dev/null @@ -1,21 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions for PAC1934 (power monitor) -DECLARE_FAKE_VALUE_FUNC(bool, PAC1934_begin); -DECLARE_FAKE_VALUE_FUNC(float, PAC1934_readVoltage, uint8_t); -DECLARE_FAKE_VALUE_FUNC(float, PAC1934_readCurrent, uint8_t); -DECLARE_FAKE_VALUE_FUNC(float, PAC1934_readPower, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PAC1934_enableChannel, uint8_t, bool); - -// Mock class for PAC1934 -class PAC1934 { -public: - bool begin() { return PAC1934_begin(); } - float readVoltage(uint8_t channel) { return PAC1934_readVoltage(channel); } - float readCurrent(uint8_t channel) { return PAC1934_readCurrent(channel); } - float readPower(uint8_t channel) { return PAC1934_readPower(channel); } - bool enableChannel(uint8_t channel, bool enable) { return PAC1934_enableChannel(channel, enable); } -}; diff --git a/test/mocks/MockPCA9634.cpp b/test/mocks/MockPCA9634.cpp deleted file mode 100644 index 4bfd766..0000000 --- a/test/mocks/MockPCA9634.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include "MockPCA9634.h" - -// Define fake functions for PCA9634 -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_begin); -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_begin_address, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_setLEDOutputMode, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_setLEDDriverMode, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_setBrightness, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCA9634_setOutputState, uint8_t, uint8_t); \ No newline at end of file diff --git a/test/mocks/MockPCA9634.h b/test/mocks/MockPCA9634.h deleted file mode 100644 index 76f41d4..0000000 --- a/test/mocks/MockPCA9634.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions for PCA9634 LED driver -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_begin); -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_begin_address, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_setLEDOutputMode, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_setLEDDriverMode, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_setBrightness, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCA9634_setOutputState, uint8_t, uint8_t); - -// Mock class for PCA9634 LED driver -class PCA9634 { -public: - bool begin() { return PCA9634_begin(); } - bool begin(uint8_t address) { return PCA9634_begin_address(address); } - bool setLEDOutputMode(uint8_t ledNum, uint8_t mode) { return PCA9634_setLEDOutputMode(ledNum, mode); } - bool setLEDDriverMode(uint8_t ledNum, uint8_t mode) { return PCA9634_setLEDDriverMode(ledNum, mode); } - bool setBrightness(uint8_t ledNum, uint8_t brightness) { return PCA9634_setBrightness(ledNum, brightness); } - bool setOutputState(uint8_t ledNum, uint8_t state) { return PCA9634_setOutputState(ledNum, state); } -}; \ No newline at end of file diff --git a/test/mocks/MockPCAL9535A.cpp b/test/mocks/MockPCAL9535A.cpp deleted file mode 100644 index 88c502f..0000000 --- a/test/mocks/MockPCAL9535A.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "MockPCAL9535A.h" - -// Define fake functions -DEFINE_FAKE_VALUE_FUNC(bool, PCAL9535A_begin); -DEFINE_FAKE_VALUE_FUNC(bool, PCAL9535A_pinMode, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCAL9535A_digitalWrite, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(uint8_t, PCAL9535A_digitalRead, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, PCAL9535A_begin_address, uint8_t); - -// Set default behavior -void setup_mock_PCAL9535A_defaults() { - PCAL9535A_begin_fake.return_val = true; - PCAL9535A_pinMode_fake.return_val = true; - PCAL9535A_digitalWrite_fake.return_val = true; - PCAL9535A_digitalRead_fake.return_val = 0; - PCAL9535A_begin_address_fake.return_val = true; -} \ No newline at end of file diff --git a/test/mocks/MockPCAL9535A.h b/test/mocks/MockPCAL9535A.h deleted file mode 100644 index 0646586..0000000 --- a/test/mocks/MockPCAL9535A.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions -DECLARE_FAKE_VALUE_FUNC(bool, PCAL9535A_begin); -DECLARE_FAKE_VALUE_FUNC(bool, PCAL9535A_pinMode, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCAL9535A_digitalWrite, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(uint8_t, PCAL9535A_digitalRead, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, PCAL9535A_begin_address, uint8_t); - -// Mock class for PCAL9535A IO expander -class PCAL9535A { -public: - bool begin() { return PCAL9535A_begin(); } - bool pinMode(uint8_t pin, uint8_t mode) { return PCAL9535A_pinMode(pin, mode); } - bool digitalWrite(uint8_t pin, uint8_t value) { return PCAL9535A_digitalWrite(pin, value); } - uint8_t digitalRead(uint8_t pin) { return PCAL9535A_digitalRead(pin); } - bool begin(uint8_t address) { return PCAL9535A_begin_address(address); } - - // Add more methods as needed for Kestrel tests -}; \ No newline at end of file diff --git a/test/mocks/MockParticle.h b/test/mocks/MockParticle.h deleted file mode 100644 index 38ba1be..0000000 --- a/test/mocks/MockParticle.h +++ /dev/null @@ -1,70 +0,0 @@ -// test/mocks/mock_particle.h -#pragma once -#include -#include -#include - -// Basic String implementation to match Particle's String class -class String { -private: - std::string data; - -public: - String() : data("") {} - String(const char* str) : data(str ? str : "") {} - String(const std::string& str) : data(str) {} - String(int value) : data(std::to_string(value)) {} - - // Common methods used in the tests - bool equals(const String& other) const { return data == other.data; } - bool startsWith(const String& prefix) const { - return data.find(prefix.data) == 0; - } - bool endsWith(const String& suffix) const { - if (suffix.data.length() > data.length()) return false; - return data.rfind(suffix.data) == (data.length() - suffix.data.length()); - } - - // Operators - String operator+(const String& rhs) const { - return String(data + rhs.data); - } - String& operator+=(const String& rhs) { - data += rhs.data; - return *this; - } - bool operator==(const String& rhs) const { - return data == rhs.data; - } - - // Conversion operators - operator const char*() const { return data.c_str(); } - - // Common String methods - size_t length() const { return data.length(); } - const char* c_str() const { return data.c_str(); } - - // Specific methods needed for your FlightControl_Demo - bool endsWith(char c) const { - return !data.empty() && data.back() == c; - } - - int lastIndexOf(char c) const { - size_t pos = data.rfind(c); - return pos != std::string::npos ? static_cast(pos) : -1; - } - - int lastIndexOf(const String& str) const { - size_t pos = data.rfind(str.data); - return pos != std::string::npos ? static_cast(pos) : -1; - } - - // Add more methods as they're needed -}; - -// Add other Particle types and functions as needed -// For example: -typedef uint8_t byte; - -// Time functions are implemented in MockArduino.cpp -// Don't define millis() here to avoid duplicate definition \ No newline at end of file diff --git a/test/mocks/MockSDI12Talon.h b/test/mocks/MockSDI12Talon.h new file mode 100644 index 0000000..e4d332a --- /dev/null +++ b/test/mocks/MockSDI12Talon.h @@ -0,0 +1,39 @@ +#ifndef MOCK_SDI12_TALON_H +#define MOCK_SDI12_TALON_H + +#include +#include "ISDI12Talon.h" + +/** + * @brief Mock implementation of the ISDI12Talon interface for testing + */ +class MockSDI12Talon : public ISDI12Talon { +public: + // SDI12 communication methods + MOCK_METHOD(int, getAddress, (), (override)); + MOCK_METHOD(String, sendCommand, (String command), (override)); + MOCK_METHOD(String, command, (String commandStr, int address), (override)); + MOCK_METHOD(int, startMeasurment, (int Address), (override)); + MOCK_METHOD(int, startMeasurmentIndex, (int index, int Address), (override)); + MOCK_METHOD(String, continuousMeasurmentCRC, (int Measure, int Address), (override)); + MOCK_METHOD(bool, testCRC, (String message), (override)); + + // Port management methods + MOCK_METHOD(int, enableData, (uint8_t port, bool state), (override)); + MOCK_METHOD(int, enablePower, (uint8_t port, bool state), (override)); + MOCK_METHOD(void, disableDataAll, (), (override)); + MOCK_METHOD(uint8_t, getNumPorts, (), (override)); + + // Sensor interrogation + MOCK_METHOD(bool, isPresent, (), (override)); + + // Error handling and state reporting + //MOCK_METHOD(int, throwError, (uint32_t error), (override)); + MOCK_METHOD(String, getSensorPortString, (), (override)); + MOCK_METHOD(String, getTalonPortString, (), (override)); + MOCK_METHOD(uint8_t, getSensorPort, (), (override)); + MOCK_METHOD(uint8_t, getTalonPort, (), (override)); + MOCK_METHOD(int, restart, (), (override)); +}; + +#endif // MOCK_SDI12_TALON_H \ No newline at end of file diff --git a/test/mocks/MockSHT4x.cpp b/test/mocks/MockSHT4x.cpp deleted file mode 100644 index f944eb3..0000000 --- a/test/mocks/MockSHT4x.cpp +++ /dev/null @@ -1,17 +0,0 @@ -#include "MockSHT4x.h" - -// Define fake functions -DEFINE_FAKE_VALUE_FUNC(bool, SHT4x_begin); -DEFINE_FAKE_VALUE_FUNC(bool, SHT4x_setPrecision, uint8_t); -DEFINE_FAKE_VALUE_FUNC(bool, SHT4x_readTemperature); -DEFINE_FAKE_VALUE_FUNC(bool, SHT4x_readHumidity); -DEFINE_FAKE_VALUE_FUNC(bool, SHT4x_getEvent); - -// Set default behavior -void setup_mock_SHT4x_defaults() { - SHT4x_begin_fake.return_val = true; - SHT4x_setPrecision_fake.return_val = true; - SHT4x_readTemperature_fake.return_val = true; - SHT4x_readHumidity_fake.return_val = true; - SHT4x_getEvent_fake.return_val = true; -} diff --git a/test/mocks/MockSHT4x.h b/test/mocks/MockSHT4x.h deleted file mode 100644 index 22081ea..0000000 --- a/test/mocks/MockSHT4x.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Constants to match Adafruit's SHT4x -#define SHT4X_HIGH_PRECISION 0 -#define SHT4X_MED_PRECISION 1 -#define SHT4X_LOW_PRECISION 2 - -// Declare fake functions -DECLARE_FAKE_VALUE_FUNC(bool, SHT4x_begin); -DECLARE_FAKE_VALUE_FUNC(bool, SHT4x_setPrecision, uint8_t); -DECLARE_FAKE_VALUE_FUNC(bool, SHT4x_readTemperature); -DECLARE_FAKE_VALUE_FUNC(bool, SHT4x_readHumidity); -DECLARE_FAKE_VALUE_FUNC(bool, SHT4x_getEvent); - -// Mock class for Adafruit_SHT4x -class Adafruit_SHT4x { -public: - float temperature = 25.0f; // Default mock values - float humidity = 50.0f; - - bool begin() { return SHT4x_begin(); } - bool setPrecision(uint8_t precision) { return SHT4x_setPrecision(precision); } - float readTemperature() { SHT4x_readTemperature(); return temperature; } - float readHumidity() { SHT4x_readHumidity(); return humidity; } - bool getEvent() { return SHT4x_getEvent(); } -}; diff --git a/test/mocks/MockSPI.cpp b/test/mocks/MockSPI.cpp deleted file mode 100644 index 430c89b..0000000 --- a/test/mocks/MockSPI.cpp +++ /dev/null @@ -1,4 +0,0 @@ -#include "SPI.h" - -// Define the extern variable -SPIClass SPI; \ No newline at end of file diff --git a/test/mocks/MockSensor.h b/test/mocks/MockSensor.h deleted file mode 100644 index 3c27298..0000000 --- a/test/mocks/MockSensor.h +++ /dev/null @@ -1,36 +0,0 @@ -#pragma once - -#include -#include "MockParticle.h" - -// This is a minimal mock of the Sensor base class that Kestrel inherits from -class Sensor { -public: - Sensor() {} - virtual ~Sensor() {} - - // Common base class properties - static constexpr int MAX_NUM_ERRORS = 10; // Maximum number of errors to log - uint32_t errors[MAX_NUM_ERRORS] = {0}; - uint8_t numErrors = 0; - bool errorOverwrite = false; - - // Common methods - virtual int throwError(uint32_t error) { - // Simple error handling implementation - if (numErrors < MAX_NUM_ERRORS) { - errors[numErrors++] = error; - } else { - errors[MAX_NUM_ERRORS - 1] = error; - errorOverwrite = true; - } - return 0; - } - - // Virtual methods that would be implemented by derived classes - virtual String begin(bool &criticalFault, bool &fault) { return ""; } - virtual String getData(void) { return ""; } - virtual String getMetadata(void) { return ""; } - virtual String getErrors(void) { return ""; } - virtual String selfDiagnostic(uint8_t diagnosticLevel) { return ""; } -}; \ No newline at end of file diff --git a/test/mocks/MockTimeProvider.h b/test/mocks/MockTimeProvider.h new file mode 100644 index 0000000..3d91242 --- /dev/null +++ b/test/mocks/MockTimeProvider.h @@ -0,0 +1,34 @@ +// tests/mocks/MockTimeProvider.h +#ifndef MOCK_TIME_PROVIDER_H +#define MOCK_TIME_PROVIDER_H + +#include "gmock/gmock.h" +#include "ITimeProvider.h" // Include the interface definition + +/** + * @brief Google Mock implementation of ITimeProvider for testing. + */ +class MockTimeProvider : public ITimeProvider { +public: + // Mock all methods defined in the interface + MOCK_METHOD(int, year, (), (override)); + MOCK_METHOD(int, year, (time_t t), (override)); + MOCK_METHOD(int, month, (), (override)); + MOCK_METHOD(int, month, (time_t t), (override)); + MOCK_METHOD(int, day, (), (override)); + MOCK_METHOD(int, day, (time_t t), (override)); + MOCK_METHOD(int, hour, (), (override)); + MOCK_METHOD(int, hour, (time_t t), (override)); + MOCK_METHOD(int, minute, (), (override)); + MOCK_METHOD(int, minute, (time_t t), (override)); + MOCK_METHOD(int, second, (), (override)); + MOCK_METHOD(int, second, (time_t t), (override)); + MOCK_METHOD(time_t, now, (), (override)); + MOCK_METHOD(void, setTime, (time_t t), (override)); + MOCK_METHOD(bool, isValid, (), (override)); + MOCK_METHOD(void, zone, (float GMT_Offset), (override)); + MOCK_METHOD(uint32_t, millis, (), (override)); + MOCK_METHOD(void, delay, (uint32_t ms), (override)); +}; + +#endif // MOCK_TIME_PROVIDER_H \ No newline at end of file diff --git a/test/mocks/MockVEML3328.cpp b/test/mocks/MockVEML3328.cpp deleted file mode 100644 index 38909fe..0000000 --- a/test/mocks/MockVEML3328.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "MockVEML3328.h" - -// Define fake functions -DEFINE_FAKE_VALUE_FUNC(bool, VEML3328_begin); -DEFINE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readRed); -DEFINE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readGreen); -DEFINE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readBlue); -DEFINE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readClear); -DEFINE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readIR); - -// Set default behavior -void setup_mock_VEML3328_defaults() { - VEML3328_begin_fake.return_val = true; - VEML3328_readRed_fake.return_val = 500; - VEML3328_readGreen_fake.return_val = 600; - VEML3328_readBlue_fake.return_val = 450; - VEML3328_readClear_fake.return_val = 800; - VEML3328_readIR_fake.return_val = 300; -} diff --git a/test/mocks/MockVEML3328.h b/test/mocks/MockVEML3328.h deleted file mode 100644 index 619355e..0000000 --- a/test/mocks/MockVEML3328.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "fff.h" -#include - -// Declare fake functions for VEML3328 (light sensor) -DECLARE_FAKE_VALUE_FUNC(bool, VEML3328_begin); -DECLARE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readRed); -DECLARE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readGreen); -DECLARE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readBlue); -DECLARE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readClear); -DECLARE_FAKE_VALUE_FUNC(uint16_t, VEML3328_readIR); - -// Mock class for VEML3328 -class VEML3328 { -public: - bool begin() { return VEML3328_begin(); } - uint16_t readRed() { return VEML3328_readRed(); } - uint16_t readGreen() { return VEML3328_readGreen(); } - uint16_t readBlue() { return VEML3328_readBlue(); } - uint16_t readClear() { return VEML3328_readClear(); } - uint16_t readIR() { return VEML3328_readIR(); } -}; diff --git a/test/mocks/MockWire.cpp b/test/mocks/MockWire.cpp deleted file mode 100644 index 2ef0b89..0000000 --- a/test/mocks/MockWire.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// test/mocks/wire_mock.cpp -#include "MockWireDeclare.h" - -// Define fake functions -DEFINE_FAKE_VOID_FUNC(Wire_begin); -DEFINE_FAKE_VOID_FUNC(Wire_setClock, unsigned long); -DEFINE_FAKE_VOID_FUNC(Wire_beginTransmission, uint8_t); -DEFINE_FAKE_VALUE_FUNC(uint8_t, Wire_endTransmission, bool); -DEFINE_FAKE_VALUE_FUNC(uint8_t, Wire_requestFrom_3args, uint8_t, uint8_t, bool); -DEFINE_FAKE_VALUE_FUNC(uint8_t, Wire_requestFrom_2args, uint8_t, uint8_t); -DEFINE_FAKE_VALUE_FUNC(int, Wire_available); -DEFINE_FAKE_VALUE_FUNC(int, Wire_read); -DEFINE_FAKE_VOID_FUNC(Wire_write_uint8, uint8_t); -DEFINE_FAKE_VOID_FUNC(Wire_write_buffer, const uint8_t*, size_t); - -// Define the global Wire instance -MockWire Wire; \ No newline at end of file diff --git a/test/mocks/MockWireDeclare.h b/test/mocks/MockWireDeclare.h deleted file mode 100644 index 334300c..0000000 --- a/test/mocks/MockWireDeclare.h +++ /dev/null @@ -1,41 +0,0 @@ -// test/mocks/mock_wire_defs.h -#ifndef WIRE_MOCK_DEFS_H -#define WIRE_MOCK_DEFS_H - -#include -#include "fff.h" - -// Declare fake functions -DECLARE_FAKE_VOID_FUNC(Wire_begin); -DECLARE_FAKE_VOID_FUNC(Wire_setClock, unsigned long); -DECLARE_FAKE_VOID_FUNC(Wire_beginTransmission, uint8_t); -DECLARE_FAKE_VALUE_FUNC(uint8_t, Wire_endTransmission, bool); -DECLARE_FAKE_VALUE_FUNC(uint8_t, Wire_requestFrom_3args, uint8_t, uint8_t, bool); -DECLARE_FAKE_VALUE_FUNC(uint8_t, Wire_requestFrom_2args, uint8_t, uint8_t); -DECLARE_FAKE_VALUE_FUNC(int, Wire_available); -DECLARE_FAKE_VALUE_FUNC(int, Wire_read); -DECLARE_FAKE_VOID_FUNC(Wire_write_uint8, uint8_t); -DECLARE_FAKE_VOID_FUNC(Wire_write_buffer, const uint8_t*, size_t); - -// Mock Wire class declaration -class MockWire { -public: - void begin() { Wire_begin(); } - void setClock(unsigned long clock) { Wire_setClock(clock); } - void beginTransmission(uint8_t address) { Wire_beginTransmission(address); } - uint8_t endTransmission(bool sendStop = true) { return Wire_endTransmission(sendStop); } - uint8_t requestFrom(uint8_t address, uint8_t quantity, bool sendStop) { - return Wire_requestFrom_3args(address, quantity, sendStop); - } - uint8_t requestFrom(uint8_t address, uint8_t quantity) { - return Wire_requestFrom_2args(address, quantity); - } - int available() { return Wire_available(); } - int read() { return Wire_read(); } - void write(uint8_t data) { Wire_write_uint8(data); } - void write(const uint8_t* data, size_t quantity) { Wire_write_buffer(data, quantity); } -}; - -extern MockWire Wire; - -#endif // WIRE_MOCK_DEFS_H \ No newline at end of file diff --git a/test/mocks/Particle.h b/test/mocks/Particle.h index 31ed9a3..03ef082 100644 --- a/test/mocks/Particle.h +++ b/test/mocks/Particle.h @@ -1,45 +1,389 @@ -#pragma once +#ifndef MOCK_PARTICLE_H +#define MOCK_PARTICLE_H -#include "MockParticle.h" -#include -#include +// This file provides a minimal mock implementation of Particle's String class +// for testing purposes, without the need for actual Particle.h -// Mock Particle types and functions to satisfy dependencies -typedef uint8_t system_event_t; +#include +#include +#include +#include +#include // For std::min and std::max -// System event handlers -constexpr system_event_t TIME_CHANGED = 1; -constexpr system_event_t LOW_MEMORY = 2; +// Forward declaration +class StringSumHelper; -// Mock Particle functions -inline void System_on(system_event_t event, void (*handler)(system_event_t, int)) { - // Just do nothing in mock -} +/** + * Mock implementation of Particle's String class for testing + * + * This class implements the minimum functionality needed for testing Li710 + * and can be expanded as needed for other components. + */ +class String { +public: + // Constructors + String(const char *cstr = "") { + if (cstr) { + _buffer = strdup(cstr); + if (_buffer) { + _length = strlen(cstr); + _capacity = _length; + } + } + } + + String(const String &str) : String(str._buffer) {} + + explicit String(char c) { + _buffer = (char*)malloc(2); + if (_buffer) { + _buffer[0] = c; + _buffer[1] = 0; + _length = 1; + _capacity = 1; + } + } + + explicit String(int value, unsigned char base = 10) { + char buf[33]; + snprintf(buf, sizeof(buf), base == 10 ? "%d" : "%x", value); + *this = String(buf); + } + + explicit String(float value, int decimalPlaces = 2) { + char buf[33]; + snprintf(buf, sizeof(buf), "%.*f", decimalPlaces, value); + *this = String(buf); + } + + ~String() { + if (_buffer) free(_buffer); + } + + // Operators + String& operator = (const String &rhs) { + if (this == &rhs) return *this; + if (_buffer) free(_buffer); + if (rhs._buffer) { + _buffer = strdup(rhs._buffer); + _length = rhs._length; + _capacity = rhs._capacity; + } else { + _buffer = nullptr; + _length = 0; + _capacity = 0; + } + return *this; + } + + String& operator = (const char *cstr) { + if (_buffer) free(_buffer); + if (cstr) { + _buffer = strdup(cstr); + _length = strlen(cstr); + _capacity = _length; + } else { + _buffer = nullptr; + _length = 0; + _capacity = 0; + } + return *this; + } + + // Concatenation + unsigned char concat(const String &str) { + return concat(str._buffer, str._length); + } + + unsigned char concat(const char *cstr) { + if (!cstr) return 0; + return concat(cstr, strlen(cstr)); + } + + unsigned char concat(const char *cstr, unsigned int length) { + if (!cstr || !length) return 0; + + unsigned int newLen = _length + length; + char *newBuffer = (char*)realloc(_buffer, newLen + 1); + if (!newBuffer) return 0; + + _buffer = newBuffer; + memcpy(_buffer + _length, cstr, length); + _buffer[newLen] = 0; + _length = newLen; + _capacity = newLen; + return 1; + } + + unsigned char concat(char c) { + char buf[2]; + buf[0] = c; + buf[1] = 0; + return concat(buf, 1); + } + + unsigned char concat(int num) { + char buf[12]; + snprintf(buf, sizeof(buf), "%d", num); + return concat(buf, strlen(buf)); + } + + unsigned char concat(float num, int decimalPlaces = 2) { + char buf[20]; + snprintf(buf, sizeof(buf), "%.*f", decimalPlaces, num); + return concat(buf, strlen(buf)); + } + + String& operator += (const String &rhs) { + concat(rhs); + return *this; + } + + String& operator += (const char *cstr) { + concat(cstr); + return *this; + } + + String& operator += (char c) { + concat(c); + return *this; + } + + String& operator += (int num) { + concat(num); + return *this; + } + + // Comparison + unsigned char equals(const String &s) const { + if (_length != s._length) return 0; + if (!_buffer || !s._buffer) return (_buffer == s._buffer); + return (strcmp(_buffer, s._buffer) == 0); + } + + unsigned char equals(const char *cstr) const { + if (!_buffer || !cstr) return (_buffer == cstr); + return (strcmp(_buffer, cstr) == 0); + } + + unsigned char operator == (const String &rhs) const { + return equals(rhs); + } + + unsigned char operator == (const char *cstr) const { + return equals(cstr); + } + + unsigned char operator != (const String &rhs) const { + return !equals(rhs); + } + + unsigned char operator != (const char *cstr) const { + return !equals(cstr); + } + + // Access + char charAt(unsigned int index) const { + if (index >= _length || !_buffer) return 0; + return _buffer[index]; + } + + void setCharAt(unsigned int index, char c) { + if (index >= _length || !_buffer) return; + _buffer[index] = c; + } + + char operator [] (unsigned int index) const { + return charAt(index); + } + + char& operator [] (unsigned int index) { + static char dummy_writable_char; + if (index >= _length || !_buffer) { + dummy_writable_char = 0; + return dummy_writable_char; + } + return _buffer[index]; + } + + const char* c_str() const { + return _buffer ? _buffer : ""; + } + + operator const char*() const { + return c_str(); + } + + unsigned int length() const { + return _length; + } + + // Search + int indexOf(char ch) const { + return indexOf(ch, 0); + } + + int indexOf(char ch, unsigned int fromIndex) const { + if (!_buffer || fromIndex >= _length) return -1; + const char* temp = strchr(_buffer + fromIndex, ch); + if (temp == nullptr) return -1; + return temp - _buffer; + } + + int indexOf(const String &str) const { + return indexOf(str, 0); + } + + int indexOf(const String &str, unsigned int fromIndex) const { + if (!_buffer || !str._buffer || fromIndex >= _length) return -1; + const char* found = strstr(_buffer + fromIndex, str._buffer); + if (found == nullptr) return -1; + return found - _buffer; + } -inline int Time_now() { - return time(NULL); -} + void toCharArray(char *buf, unsigned int bufsize, unsigned int index = 0) const { + if (buf == nullptr || bufsize == 0) { + return; // Nothing to do + } -inline bool Particle_connected() { - return true; -} + // Always null-terminate the start of the buffer + buf[0] = '\0'; -inline bool Particle_syncTime() { - return true; -} + // Check if the source buffer is valid and index is within bounds + if (_buffer == nullptr || index >= _length) { + return; // Nothing to copy + } + + // How many characters are available in the source string from index? + size_t source_available = _length - index; + + // How many characters can we actually copy? (Need bufsize - 1 for the null terminator) + size_t copy_len = std::min(source_available, (size_t)(bufsize - 1)); -// Define the actual Particle API namespace/functions -namespace Particle { - inline bool connected() { return Particle_connected(); } - inline bool syncTime() { return Particle_syncTime(); } + // Perform the copy from the internal buffer + if (copy_len > 0) { // Only copy if there's something to copy + memcpy(buf, _buffer + index, copy_len); + } + + // Add the null terminator at the end of the copied content + buf[copy_len] = '\0'; + } + + // Modification + String substring(unsigned int beginIndex) const { + if (!_buffer || beginIndex >= _length) return String(); + return String(_buffer + beginIndex); + } + + String substring(unsigned int beginIndex, unsigned int endIndex) const { + if (!_buffer || beginIndex >= _length || endIndex <= beginIndex) return String(); + if (endIndex > _length) endIndex = _length; + char temp[endIndex - beginIndex + 1]; + strncpy(temp, _buffer + beginIndex, endIndex - beginIndex); + temp[endIndex - beginIndex] = 0; + return String(temp); + } + + String& remove(unsigned int index) { + if (!_buffer || index >= _length) return *this; + memmove(_buffer + index, _buffer + index + 1, _length - index); + _length--; + _buffer[_length] = 0; + return *this; + } + + String& remove(unsigned int index, unsigned int count) { + if (!_buffer || index >= _length) return *this; + if (count > _length - index) count = _length - index; + memmove(_buffer + index, _buffer + index + count, _length - index - count + 1); + _length -= count; + return *this; + } + + String& replace(char find, char replace) { + if (!_buffer) return *this; + for (unsigned int i = 0; i < _length; i++) { + if (_buffer[i] == find) _buffer[i] = replace; + } + return *this; + } - namespace System { - inline void on(system_event_t event, void (*handler)(system_event_t, int)) { - System_on(event, handler); + String& trim() { + if (!_buffer || !_length) return *this; + + // Find start of non-whitespace + char *begin = _buffer; + while (isspace(*begin)) begin++; + + // Find end of non-whitespace + char *end = _buffer + _length - 1; + while (end > begin && isspace(*end)) end--; + + // Calculate new length + unsigned int newlen = end - begin + 1; + + // Move string if needed + if (begin > _buffer) { + memmove(_buffer, begin, newlen); } + + // Add null terminator + _buffer[newlen] = 0; + _length = newlen; + + return *this; } - namespace Time { - inline int now() { return Time_now(); } + // Parsing + long toInt() const { + if (!_buffer) return 0; + return atol(_buffer); } -} \ No newline at end of file + + float toFloat() const { + if (!_buffer) return 0; + return atof(_buffer); + } + +private: + char* _buffer = nullptr; + unsigned int _length = 0; + unsigned int _capacity = 0; +}; + +// String helper class for concatenation operations +class StringSumHelper : public String { +public: + StringSumHelper(const String &s) : String(s) {} + StringSumHelper(const char *p) : String(p) {} + StringSumHelper(char c) : String(c) {} + StringSumHelper(int num) : String(num) {} + StringSumHelper(float num) : String(num) {} +}; + +// Concatenation operators +inline StringSumHelper operator + (const String &lhs, const String &rhs) { + StringSumHelper result(lhs); + result += rhs; + return result; +} + +inline StringSumHelper operator + (const String &lhs, const char *cstr) { + StringSumHelper result(lhs); + result += cstr; + return result; +} + +inline StringSumHelper operator + (const String &lhs, char c) { + StringSumHelper result(lhs); + result += c; + return result; +} + +inline StringSumHelper operator + (const String &lhs, int num) { + StringSumHelper result(lhs); + result += num; + return result; +} + +#endif // MOCK_PARTICLE_H diff --git a/test/mocks/SPI.h b/test/mocks/SPI.h deleted file mode 100644 index 1f4fc88..0000000 --- a/test/mocks/SPI.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once - -#include -#include // For size_t - -// SPI settings -#define SPI_MODE0 0x00 -#define SPI_MODE1 0x01 -#define SPI_MODE2 0x02 -#define SPI_MODE3 0x03 - -#define SPI_CLOCK_DIV2 0x00 -#define SPI_CLOCK_DIV4 0x01 -#define SPI_CLOCK_DIV8 0x02 -#define SPI_CLOCK_DIV16 0x03 -#define SPI_CLOCK_DIV32 0x04 -#define SPI_CLOCK_DIV64 0x05 -#define SPI_CLOCK_DIV128 0x06 - -// Simple mock for the SPI class -class SPIClass { -public: - void begin() {} - void beginTransaction(uint32_t settings) {} - void endTransaction() {} - uint8_t transfer(uint8_t data) { return 0; } - void transfer(void *buf, size_t count) {} -}; - -extern SPIClass SPI; \ No newline at end of file diff --git a/test/mocks/TestKestrel.h b/test/mocks/TestKestrel.h deleted file mode 100644 index 8898d5f..0000000 --- a/test/mocks/TestKestrel.h +++ /dev/null @@ -1,336 +0,0 @@ -#pragma once - -// Modified Kestrel.h intended for testing only -// This provides a controlled environment without class redefinitions - -// Include all mocks we need -#include "MockArduino.h" -#include "MockSensor.h" -#include "MockPCAL9535A.h" -#include "MockPCA9634.h" -#include "MockMCP79412.h" -#include "MockGNSS.h" -#include "MockPAC1934.h" -#include "MockVEML3328.h" -#include "MockSHT4x.h" -#include "MockMXC6655.h" -#include "MockBMA456.h" -#include "MockWireDeclare.h" - -// Define constants and namespaces from Kestrel.h that we need for testing -namespace Pins { - constexpr uint16_t WD_HOLD = D2; - constexpr uint16_t SD_CS = D8; - constexpr uint16_t Clock_INT = D22; - constexpr uint16_t TALON1_GPIOA = A3; - constexpr uint16_t TALON1_GPIOB = D7; - constexpr uint16_t TALON2_GPIOA = A2; - constexpr uint16_t TALON2_GPIOB = D6; - constexpr uint16_t TALON3_GPIOA = A1; - constexpr uint16_t TALON3_GPIOB = D5; - constexpr uint16_t I2C_GLOBAL_EN = D23; - constexpr uint16_t I2C_OB_EN = A6; -} - -namespace PinsOB { - constexpr uint16_t I2C_EXT_EN = 10; - constexpr uint16_t SD_CD = 8; - constexpr uint16_t SD_EN = 12; - constexpr uint16_t AUX_EN = 15; - constexpr uint16_t CE = 11; - constexpr uint16_t LED_EN = 13; - constexpr uint16_t CSA_EN = 14; - constexpr uint16_t GPS_INT = 7; -} - -namespace PinsTalon { - constexpr uint8_t SEL[4] = {0, 4, 8, 12}; - constexpr uint8_t I2C_EN[4] = {1, 5, 9, 13}; - constexpr uint8_t EN[4] = {3, 7, 11, 15}; - constexpr uint8_t FAULT[4] = {2, 6, 10, 14}; -} - -namespace TimeSource { - constexpr uint8_t INCREMENT = 4; - constexpr uint8_t RTC = 3; - constexpr uint8_t GPS_RTC = 2; - constexpr uint8_t CELLULAR = 1; - constexpr uint8_t GPS = 0; - constexpr uint8_t NONE = 5; -} - -namespace IndicatorLight { - constexpr uint8_t SENSORS = 1; - constexpr uint8_t GPS = 2; - constexpr uint8_t CELL = 3; - constexpr uint8_t STAT = 4; - constexpr uint8_t ALL = 5; -} - -namespace IndicatorMode { - constexpr uint8_t NONE = 0; - constexpr uint8_t PASS = 1; - constexpr uint8_t WAITING = 2; - constexpr uint8_t ERROR = 3; - constexpr uint8_t ERROR_CRITICAL = 4; - constexpr uint8_t PREPASS = 5; - constexpr uint8_t INIT = 6; - constexpr uint8_t IDLE = 7; - constexpr uint8_t COMMAND = 8; -} - -namespace AccelType { - constexpr uint8_t MXC6655 = 0; - constexpr uint8_t BMA456 = 1; -} - -namespace HardwareVersion { - constexpr uint8_t PRE_1v9 = 0; - constexpr uint8_t MODEL_1v9 = 1; -} - -struct dateTimeStruct { - int year; - int month; - int day; - int hour; - int minute; - int second; - uint8_t source = TimeSource::NONE; -}; - -// Simplified version of Kestrel for testing -// We'll manually implement the methods we want to test -class Kestrel : public Sensor { -public: - constexpr static int MAX_NUM_ERRORS = 10; - const std::string FIRMWARE_VERSION = "1.7.5"; - static constexpr uint8_t numTalonPorts = 5; - static constexpr int MAX_MESSAGE_LENGTH = 1024; - - dateTimeStruct currentDateTime = {2049, 6, 16, 3, 27, 31, TimeSource::NONE}; - uint8_t timeFix = 0; - SFE_UBLOX_GNSS gps; - - // Constructor - Kestrel(bool useSensors = false) : reportSensors(useSensors) { - // Initialize member objects - } - - // Public methods we want to test - std::string begin(time_t time, bool &criticalFault, bool &fault) { - // Call internal device initializations - ioOB.begin(); - ioTalon.begin(); - rtc.begin(); - led.begin(); - - if (reportSensors) { - als.begin(); - csaAlpha.begin(); - csaBeta.begin(); - atmos.begin(); - accel.begin(); - gps.begin(); - } - - // Return success message - return "Kestrel " + FIRMWARE_VERSION + " initialized successfully"; - } - - bool enablePower(uint8_t port, bool state = true) { - if (port >= numTalonPorts) return false; - - // Call IO expander to enable/disable power - return ioTalon.digitalWrite(PinsTalon::EN[port], state); - } - - bool enableData(uint8_t port, bool state = true) { - if (port >= numTalonPorts) return false; - - // Call IO expander to enable/disable data - return ioTalon.digitalWrite(PinsTalon::I2C_EN[port], state); - } - - time_t getTime() { - return rtc.getTime(); - } - - bool enableI2C_OB(bool state = true) { - return ioOB.digitalWrite(PinsOB::I2C_EXT_EN, state); - } - - bool enableI2C_Global(bool state = true) { - // In our mock environment, digitalWrite returns void - // But in the real implementation it would return a status - digitalWrite(Pins::I2C_GLOBAL_EN, state); - return true; // Assume success - } - - bool enableI2C_External(bool state = true) { - return ioOB.digitalWrite(PinsOB::I2C_EXT_EN, state); - } - - bool setIndicatorState(uint8_t ledBank, uint8_t mode) { - int brightness = 0; - - // Convert mode to brightness - switch (mode) { - case IndicatorMode::PASS: - brightness = 75; - break; - case IndicatorMode::ERROR: - brightness = 100; - break; - default: - brightness = 0; - break; - } - - return led.setBrightness(ledBank, brightness); - } - - // Other methods as needed for testing... - -private: - PCAL9535A ioOB; - PCAL9535A ioTalon; - MCP79412 rtc; - PAC1934 csaAlpha; - PAC1934 csaBeta; - VEML3328 als; - Adafruit_SHT4x atmos; - MXC6655 accel; - PCA9634 led; - bool reportSensors = false; -}; - -// Helper functions for testing Kestrel -namespace KestrelTest { - // Setup a Kestrel instance with all mock dependencies properly configured - inline Kestrel* createKestrel() { - // Configure all mock return values for a successful initialization - PCAL9535A_begin_fake.return_val = true; - MCP79412_begin_fake.return_val = true; - MCP79412_getTime_fake.return_val = 1616161616; - PCA9634_begin_fake.return_val = true; - VEML3328_begin_fake.return_val = true; - PAC1934_begin_fake.return_val = true; - SHT4x_begin_fake.return_val = true; - MXC6655_begin_fake.return_val = true; - BMA456_begin_fake.return_val = true; - GNSS_begin_fake.return_val = true; - - // Create a Kestrel instance - return new Kestrel(true); // true = use sensors - } - - // Reset all mocks for a clean slate - inline void resetAllMocks() { - // Wire mocks - RESET_FAKE(Wire_begin); - RESET_FAKE(Wire_setClock); - RESET_FAKE(Wire_beginTransmission); - RESET_FAKE(Wire_endTransmission); - RESET_FAKE(Wire_requestFrom_3args); - RESET_FAKE(Wire_requestFrom_2args); - RESET_FAKE(Wire_available); - RESET_FAKE(Wire_read); - RESET_FAKE(Wire_write_uint8); - RESET_FAKE(Wire_write_buffer); - - // Arduino mocks - RESET_FAKE(pinMode); - RESET_FAKE(digitalWrite); - RESET_FAKE(digitalRead); - RESET_FAKE(millis); - RESET_FAKE(delay); - - // Hardware component mocks - RESET_FAKE(PCAL9535A_begin); - RESET_FAKE(PCAL9535A_pinMode); - RESET_FAKE(PCAL9535A_digitalWrite); - RESET_FAKE(PCAL9535A_digitalRead); - - RESET_FAKE(MCP79412_begin); - RESET_FAKE(MCP79412_getTime); - RESET_FAKE(MCP79412_setTime); - - RESET_FAKE(PCA9634_begin); - RESET_FAKE(PCA9634_setBrightness); - RESET_FAKE(PCA9634_setLEDOutputMode); - - RESET_FAKE(VEML3328_begin); - RESET_FAKE(VEML3328_readRed); - RESET_FAKE(VEML3328_readGreen); - RESET_FAKE(VEML3328_readBlue); - - RESET_FAKE(PAC1934_begin); - RESET_FAKE(PAC1934_readVoltage); - RESET_FAKE(PAC1934_readCurrent); - - RESET_FAKE(SHT4x_begin); - RESET_FAKE(SHT4x_readTemperature); - RESET_FAKE(SHT4x_readHumidity); - - RESET_FAKE(MXC6655_begin); - RESET_FAKE(MXC6655_readAcceleration); - - RESET_FAKE(BMA456_begin); - RESET_FAKE(BMA456_readAcceleration); - RESET_FAKE(BMA456_getStepCount); - - RESET_FAKE(GNSS_begin); - RESET_FAKE(GNSS_getLatitude); - RESET_FAKE(GNSS_getLongitude); - RESET_FAKE(GNSS_getAltitude); - } - - // Set default successful return values for hardware operations - inline void setDefaultMockBehavior() { - // Configure default successful behaviors - Wire_endTransmission_fake.return_val = 0; // Success - Wire_available_fake.return_val = 1; // Data available - - PCAL9535A_begin_fake.return_val = true; - PCAL9535A_digitalWrite_fake.return_val = true; - PCAL9535A_digitalRead_fake.return_val = 0; // Default to LOW - - MCP79412_begin_fake.return_val = true; - MCP79412_getTime_fake.return_val = 1616161616; - MCP79412_setTime_fake.return_val = true; - - PCA9634_begin_fake.return_val = true; - PCA9634_setBrightness_fake.return_val = true; - PCA9634_setLEDOutputMode_fake.return_val = true; - - VEML3328_begin_fake.return_val = true; - VEML3328_readRed_fake.return_val = 500; - VEML3328_readGreen_fake.return_val = 600; - VEML3328_readBlue_fake.return_val = 400; - - PAC1934_begin_fake.return_val = true; - PAC1934_readVoltage_fake.return_val = 3.3f; - PAC1934_readCurrent_fake.return_val = 0.1f; - - SHT4x_begin_fake.return_val = true; - - MXC6655_begin_fake.return_val = true; - BMA456_begin_fake.return_val = true; - - GNSS_begin_fake.return_val = true; - GNSS_isConnected_fake.return_val = true; - GNSS_getLatitude_fake.return_val = 449673925; - GNSS_getLongitude_fake.return_val = -932838386; - GNSS_getAltitude_fake.return_val = 25000; - GNSS_getSIV_fake.return_val = 8; - GNSS_getYear_fake.return_val = 2023; - GNSS_getMonth_fake.return_val = 5; - GNSS_getDay_fake.return_val = 15; - GNSS_getHour_fake.return_val = 10; - GNSS_getMinute_fake.return_val = 30; - GNSS_getSecond_fake.return_val = 0; - - millis_fake.return_val = 1000; // Start at 1 second - } -} \ No newline at end of file diff --git a/test/mocks/WProgram.h b/test/mocks/WProgram.h deleted file mode 100644 index f638a01..0000000 --- a/test/mocks/WProgram.h +++ /dev/null @@ -1,4 +0,0 @@ -#pragma once - -// This is for older Arduino code that used WProgram.h instead of Arduino.h -#include "Arduino.h" \ No newline at end of file diff --git a/test/mocks/Wire.h b/test/mocks/Wire.h deleted file mode 100644 index 993e1f4..0000000 --- a/test/mocks/Wire.h +++ /dev/null @@ -1,5 +0,0 @@ -#pragma once - -#include "MockWireDeclare.h" - -// This is just a header to include our Wire mock \ No newline at end of file diff --git a/test/unit/Driver_-_Li710/Li710Test.cpp b/test/unit/Driver_-_Li710/Li710Test.cpp new file mode 100644 index 0000000..d6b95d7 --- /dev/null +++ b/test/unit/Driver_-_Li710/Li710Test.cpp @@ -0,0 +1,423 @@ +#include +#include + +#include "Particle.h" //this is a mock of Particle.h that only includes its string implementation + +// Include other mocks +#include "MockSDI12Talon.h" +#include "MockTimeProvider.h" + +// Include the actual implementation +#include "Li710.h" + +class Li710Test : public ::testing::Test { +protected: + // Our mock objects + MockSDI12Talon mockTalon; + MockTimeProvider mockTimeProvider; + + void SetUp() override { + // Set up common mock behavior + ON_CALL(mockTalon, getSensorPortString()) + .WillByDefault(::testing::Return("1")); + ON_CALL(mockTalon, getTalonPortString()) + .WillByDefault(::testing::Return("1")); + ON_CALL(mockTalon, getSensorPort()) + .WillByDefault(::testing::Return(1)); + ON_CALL(mockTalon, getTalonPort()) + .WillByDefault(::testing::Return(1)); + } +}; + +// verify sensor interface set to SDI12 +TEST_F(Li710Test, TestSensorInterfaceSdi12) { + // Create a Li710 instance with our mock + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + // Verify that the sensor interface is set to SDI12 + EXPECT_EQ(li710.sensorInterface, BusType::SDI12); +} + +//verify talon port set to 255 if not in range +TEST_F(Li710Test, TestTalonPortOutOfRange) { + // Create a Li710 instance with our mock + LI710 li710(mockTimeProvider, mockTalon, 0, 1); // Set an out-of-range talon port + + // Verify that getTalonPort returns 0 when the port is 255 + EXPECT_EQ(li710.getTalonPort(), 0); +} + +//verify sensor port set to 255 if not in range +TEST_F(Li710Test, TestSensorPortOutOfRange) { + // Create a Li710 instance with our mock + LI710 li710(mockTimeProvider, mockTalon, 1, 0); // Set an out-of-range sensor port + + // Verify that getTalonPort returns 0 when the port is 255 + EXPECT_EQ(li710.getSensorPort(), 0); +} + +//verify talonPort is talonPort_ - 1 +TEST_F(Li710Test, TestTalonPortSet) { + // Create a Li710 instance with our mock + LI710 li710(mockTimeProvider, mockTalon, 42, 1); // Set a valid talon port + + // Verify that the talon port is set correctly + EXPECT_EQ(li710.getTalonPort(), 42); +} + +//verify sensorPort is sensorPort_ - 1 +TEST_F(Li710Test, TestSensorPortSet) { + // Create a Li710 instance with our mock + LI710 li710(mockTimeProvider, mockTalon, 1, 42); // Set a valid talon port + + // Verify that the sensor port is set correctly + EXPECT_EQ(li710.getSensorPort(), 42); +} + +// verify begin returns empty string +TEST_F(Li710Test, TestBegin) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + bool criticalFault = false; + bool fault = false; + + String result = li710.begin(0, criticalFault, fault); + + EXPECT_EQ(result, ""); +} + +// Test isPresent method when sensor is present +TEST_F(Li710Test, TestIsPresent_SensorFound) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillOnce(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillOnce(::testing::Return("013LI-COR LI-7101.01234567")); + + bool result = li710.isPresent(); + + EXPECT_TRUE(result); +} + +// Test isPresent method when sensor is not found +TEST_F(Li710Test, TestIsPresent_SensorNotFound) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillOnce(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillOnce(::testing::Return("013UNKNOWN SENSOR1.01234567")); + + bool result = li710.isPresent(); + + EXPECT_FALSE(result); +} + +//verify isPresent is called three times when it only returns false +TEST_F(Li710Test, TestGetData_SensorNotFound) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .Times(3) + .WillRepeatedly(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .Times(3) + .WillRepeatedly(::testing::Return("013UNKNOWN SENSOR1.01234567")); + + li710.getData(0); +} + +//verify talon.getAddress is called three times when it only return -1 +TEST_F(Li710Test, TestGetData_TalonAddressFail) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .Times(3) + .WillRepeatedly(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .Times(3) + .WillRepeatedly(::testing::Return("013LI-COR LI-7101.01234567")); + + EXPECT_CALL(mockTalon, getAddress()) + .Times(3) + .WillRepeatedly(::testing::Return(-1)); + + li710.getData(0); +} + +//verify ouptut is null when sensorPort is 0 +TEST_F(Li710Test, TestGetData_SensorPortZero) { + LI710 li710(mockTimeProvider, mockTalon, 1, 0); // Set an out-of-range sensor port + + String result = li710.getData(0); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"ET\":null") > 0); + EXPECT_TRUE(result.indexOf("}") > 0); +} + +//verify output is null when retry count is reached +TEST_F(Li710Test, TestGetData_RetryCountReached) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .Times(3) + .WillRepeatedly(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .Times(3) + .WillRepeatedly(::testing::Return("013UNKNOWN SENSOR1.01234567")); + + String result = li710.getData(0); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"ET\":null") > 0); + EXPECT_TRUE(result.indexOf("}") > 0); +} + +// Test getData method with valid data +TEST_F(Li710Test, DISABLED_TestGetData_ValidData) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillOnce(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillOnce(::testing::Return("013LI-COR LI-7101.01234567")); + + EXPECT_CALL(mockTalon, getAddress()) + .WillOnce(::testing::Return(0)); + + EXPECT_CALL(mockTalon, command(String("XT"), 0)) + .WillOnce(::testing::Return("")); + + // Mock valid responses for data + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(0, 0)) + .WillOnce(::testing::Return("0+1.23+4.56+7.89+10.11+12.13+14.15+16.17+18.19+20.21")); + + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(1, 0)) + .WillOnce(::testing::Return("0+22.23+24.25+26.27+28.29+30.31+32.33+34.35+36.37+38.39")); + + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(2, 0)) + .WillOnce(::testing::Return("0+40.41+42.43+44.45+46.47+48.49+50.51+52.53+54.55")); + + EXPECT_CALL(mockTalon, testCRC(::testing::_)) + .WillRepeatedly(::testing::Return(true)); + + String result = li710.getData(0); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"ET\":1.230") > 0); + EXPECT_TRUE(result.indexOf("\"LE\":4.6") > 0); + EXPECT_TRUE(result.indexOf("\"H\":7.9") > 0); + EXPECT_TRUE(result.indexOf("\"VPD\":10.11") > 0); + EXPECT_TRUE(result.indexOf("\"PA\":12.13") > 0); + EXPECT_TRUE(result.indexOf("\"TA\":14.15") > 0); + EXPECT_TRUE(result.indexOf("\"RH\":16.17") > 0); + EXPECT_TRUE(result.indexOf("\"SAMP_CNT\":36") > 0); + EXPECT_TRUE(result.indexOf("\"AH\":40.41") > 0); + EXPECT_TRUE(result.indexOf("\"SVP\":44.45") > 0); + EXPECT_TRUE(result.indexOf("\"TD\":54.55") > 0); + EXPECT_TRUE(result.indexOf("\"Pos\":[1,1]") > 0); +} + +// Test getData method with valid data and start measurment +//after new read method +TEST_F(Li710Test, TestGetData_ValidDataStartMeasurment) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillOnce(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillOnce(::testing::Return("013LI-COR LI-7101.01234567")); + + EXPECT_CALL(mockTalon, getAddress()) + .WillOnce(::testing::Return(0)); + + EXPECT_CALL(mockTalon, command(String("XT"), 0)) + .WillOnce(::testing::Return("")); + + // Mock valid responses for data + EXPECT_CALL(mockTalon, startMeasurmentIndex(0 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(1 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(2 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(3 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, command(String("D0"), 0)) + .WillOnce(::testing::Return("0+1.23+4.56+7.89")) + .WillOnce(::testing::Return("0+22.23+24.25+26.27")) + .WillOnce(::testing::Return("0+40.41+42.43+44.45")) + .WillOnce(::testing::Return("0+40.41+42.43+44.45")); //value tbd + + EXPECT_CALL(mockTalon, command(String("D1"), 0)) + .WillOnce(::testing::Return("0+10.11+12.13+14.15")) + .WillOnce(::testing::Return("0+28.29+30.31+32.33")) + .WillOnce(::testing::Return("0+46.47+48.49+50.51")) + .WillOnce(::testing::Return("0+46.47+48.49+50.51")); //value tbd + + EXPECT_CALL(mockTalon, command(String("D2"), 0)) + .WillOnce(::testing::Return("0+16.17+18.19+20.21")) + .WillOnce(::testing::Return("0+34.35+36.37+38.39")) + .WillOnce(::testing::Return("0+52.53+54.55")) + .WillOnce(::testing::Return("0+52.53+54.55")); //value tbd + + String result = li710.getData(0); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"ET\":1.230") > 0); + EXPECT_TRUE(result.indexOf("\"LE\":4.6") > 0); + EXPECT_TRUE(result.indexOf("\"H\":7.9") > 0); + EXPECT_TRUE(result.indexOf("\"VPD\":10.11") > 0); + EXPECT_TRUE(result.indexOf("\"PA\":12.13") > 0); + EXPECT_TRUE(result.indexOf("\"TA\":14.15") > 0); + EXPECT_TRUE(result.indexOf("\"RH\":16.17") > 0); + EXPECT_TRUE(result.indexOf("\"SAMP_CNT\":36") > 0); + EXPECT_TRUE(result.indexOf("\"AH\":40.41") > 0); + EXPECT_TRUE(result.indexOf("\"SVP\":44.45") > 0); + EXPECT_TRUE(result.indexOf("\"TD\":54.55") > 0); + EXPECT_TRUE(result.indexOf("\"Pos\":[1,1]") > 0); +} + +// Test getData method with CRC failure +//disabled after new read method +TEST_F(Li710Test, DISABLED_TestGetData_CRCFailure) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .Times(3) + .WillRepeatedly(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .Times(3) + .WillRepeatedly(::testing::Return("013LI-COR LI-7101.01234567")); + + EXPECT_CALL(mockTalon, getAddress()) + .WillRepeatedly(::testing::Return(0)); + + EXPECT_CALL(mockTalon, command(String("XT"), 0)) + .WillRepeatedly(::testing::Return("")); + + // Mock valid responses for data + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(0, 0)) + .WillRepeatedly(::testing::Return("0+1.23+4.56+7.89+10.11+12.13+14.15+16.17+18.19+20.21")); + + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(1, 0)) + .WillRepeatedly(::testing::Return("0+22.23+24.25+26.27+28.29+30.31+32.33+34.35+36.37+38.39")); + + EXPECT_CALL(mockTalon, continuousMeasurmentCRC(2, 0)) + .WillRepeatedly(::testing::Return("0+40.41+42.43+44.45+46.47+48.49+50.51+52.53+54.55")); + + // Force CRC failure + EXPECT_CALL(mockTalon, testCRC(::testing::_)) + .WillRepeatedly(::testing::Return(false)); + + // Expect error to be reported + //EXPECT_CALL(mockTalon, throwError(::testing::_)) + //.Times(::testing::AtLeast(1)); + + String result = li710.getData(0); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"ET\":null") > 0); + EXPECT_TRUE(result.indexOf("\"LE\":null") > 0); + EXPECT_TRUE(result.indexOf("\"Pos\":[1,1]") > 0); +} + +// Test getMetadata method +// refactor this after refactoring Li710 +TEST_F(Li710Test, TestGetMetadata) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillOnce(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillOnce(::testing::Return("013LI-COR LI-7101.01234567")); + + String result = li710.getMetadata(); + + EXPECT_TRUE(result.indexOf("LiCor ET\":{") > 0); + EXPECT_TRUE(result.indexOf("\"Hardware\":\"1.0\"") > 0); + EXPECT_TRUE(result.indexOf("\"SDI12_Ver\":\"1.3\"") > 0); + EXPECT_TRUE(result.indexOf("\"Mfg\":\"LI-COR\"") > 0); + EXPECT_TRUE(result.indexOf("\"Model\":\"LI-710\"") > 0); + EXPECT_TRUE(result.indexOf("\"SN\":\"1234567\"") > 0); + EXPECT_TRUE(result.indexOf("\"Pos\":[1,1]") > 0); + EXPECT_TRUE(result.indexOf("}") > 0); +} + +// Test selfDiagnostic method +TEST_F(Li710Test, TestSelfDiagnostic) { + LI710 li710(mockTimeProvider, mockTalon, 1, 1); + + EXPECT_CALL(mockTalon, sendCommand(String("?!"))) + .WillRepeatedly(::testing::Return("0")); + + EXPECT_CALL(mockTalon, command(String("I"), 0)) + .WillRepeatedly(::testing::Return("013LI-COR LI-7101.01234567")); + + EXPECT_CALL(mockTalon, getAddress()) + .WillOnce(::testing::Return(0)); + + EXPECT_CALL(mockTalon, command(String("XT"), 0)) + .WillOnce(::testing::Return("")); + + // Mock valid responses for data + EXPECT_CALL(mockTalon, startMeasurmentIndex(0 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(1 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(2 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, startMeasurmentIndex(3 , 0)) + .WillOnce(::testing::Return(10)); + + EXPECT_CALL(mockTalon, command(String("D0"), 0)) + .WillOnce(::testing::Return("0+1.23+4.56+7.89")) + .WillOnce(::testing::Return("0+22.23+24.25+26.27")) + .WillOnce(::testing::Return("0+40.41+42.43+44.45")) + .WillOnce(::testing::Return("0+56.57+58.59+60.61")); //value tbd + + EXPECT_CALL(mockTalon, command(String("D1"), 0)) + .WillOnce(::testing::Return("0+10.11+12.13+14.15")) + .WillOnce(::testing::Return("0+28.29+30.31+32.33")) + .WillOnce(::testing::Return("0+46.47+48.49+50.51")) + .WillOnce(::testing::Return("0+62.63+64.65+66.67")); //value tbd + + EXPECT_CALL(mockTalon, command(String("D2"), 0)) + .WillOnce(::testing::Return("0+16.17+18.19+20.21")) + .WillOnce(::testing::Return("0+34.35+36.37+38.39")) + .WillOnce(::testing::Return("0+52.53+54.55")) + .WillOnce(::testing::Return("0+68.69+70.71")); //value tbd + + li710.getData(0); + + String result = li710.selfDiagnostic(5, 0); + + EXPECT_TRUE(result.indexOf("\"LiCor ET\":{") >= 0); + EXPECT_TRUE(result.indexOf("\"Adr\":0") > 0); + EXPECT_TRUE(result.indexOf("\"PUMP_V\":56.57") > 0); + EXPECT_TRUE(result.indexOf("\"PA_CELL\":58.59") > 0); + EXPECT_TRUE(result.indexOf("\"RH_CELL\":60.61") > 0); + EXPECT_TRUE(result.indexOf("\"TA_CELL\":62.63") > 0); + //I think this is not 70.71 because the precision value is 0 + //instead of 2. I think the fake string implementation gets rid + //of the digits before the decimal place instead of after + EXPECT_TRUE(result.indexOf("\"DATA_QC\":71") > 0); + EXPECT_TRUE(result.indexOf("\"Pos\":[1,1]") > 0); +} \ No newline at end of file