The Frankly Bootloader includes a comprehensive testing suite to ensure reliability and correctness.
tests/
├── CMakeLists.txt # Test build configuration
├── frankly_test_utils/ # Shared testing utilities
└── src/ # Test source files
├── francor/
│ └── franklyboot/
│ ├── test_handler.cpp # Core handler tests
│ ├── test_msg.cpp # Message protocol tests
│ └── test_integration.cpp # Integration tests
└── ...
# Build and run all tests
cd build
cmake ..
make
ctest
# Run specific test categories
ctest -R "handler" # Run handler tests only
ctest -R "msg" # Run message tests only
ctest -V # Verbose output- Handler Tests: Core bootloader logic validation
- Message Tests: Protocol parsing and validation
- Utility Tests: Helper function verification
- End-to-End Communication: Full request/response cycles
- Flash Operation Simulation: Virtual flash memory testing
- Error Condition Testing: Comprehensive error handling
- Device Simulator: Mock hardware interface implementation
- CRC Validation: Cryptographic hash verification
- Memory Layout: Flash organization testing
Located in utils/device_sim_api/, this tool provides:
Purpose: Software simulation of bootloader hardware for development and testing
Features:
- Virtual flash memory simulation
- CRC calculation implementation
- Device information mocking
- Communication interface simulation
Usage:
#include "device_sim_api.h"
// Create simulated device
DeviceSimulator sim(flash_size, page_size);
// Simulate hardware operations
sim.writeFlashPage(page_id, data);
uint32_t crc = sim.calculateCRC(address, size);Located in utils/can_network_sim/, provides:
Purpose: Simulation of CAN bus communication for multi-device testing
Features:
- Multi-node CAN network simulation
- Message routing and filtering
- Timing and latency simulation
- Error injection for robustness testing
Use Cases:
- Testing bootloader behavior in multi-device networks
- Protocol validation across different node configurations
- Performance and timing analysis
# Clone repository
git clone <repository-url>
cd frankly-bootloader
# Create build directory
mkdir build && cd build
# Configure with development options
cmake -DCMAKE_BUILD_TYPE=Debug ..
# Build
make -j$(nproc)
# Run tests
ctestThe project follows strict coding standards:
C++ Standard: C++17
Style: Configured via .clang-format
Static Analysis: .clang-tidy configuration provided
Formatting:
# Format all source files
find . -name "*.cpp" -o -name "*.h" | xargs clang-format -i
# Check formatting
find . -name "*.cpp" -o -name "*.h" | xargs clang-format --dry-runStatic Analysis:
# Run clang-tidy
clang-tidy src/**/*.cpp -- -std=c++17 -I include/- Add enum to
msg.h:
enum RequestType : uint16_t {
// ... existing requests ...
REQ_MY_NEW_REQUEST = 0x2000U,
};- Add handler method to
handler.h:
void handleReqMyNewRequest(const msg::Msg& request);- Implement in
handler.tpp:
template <uint32_t FLASH_START, uint32_t FLASH_APP_FIRST_PAGE,
uint32_t FLASH_SIZE, uint32_t FLASH_PAGE_SIZE>
void Handler<FLASH_START, FLASH_APP_FIRST_PAGE, FLASH_SIZE, FLASH_PAGE_SIZE>
::handleReqMyNewRequest(const msg::Msg& request) {
// Implementation
}- Add to request dispatch in
processRequest() - Create documentation in
docs/protocol/RequestTypes/ - Add tests in
tests/src/
- Add declaration to
hardware_interface.h - Update all platform implementations
- Add simulation support in
utils/device_sim_api/ - Add tests for new functionality
// Example test structure
#include <gtest/gtest.h>
#include <francor/franklyboot/handler.h>
class HandlerTest : public ::testing::Test {
protected:
using TestHandler = franklyboot::Handler<0x08000000, 32, 131072, 2048>;
TestHandler handler;
};
TEST_F(HandlerTest, NewRequestHandling) {
franklyboot::msg::Msg request{
franklyboot::msg::REQ_MY_NEW_REQUEST,
franklyboot::msg::RES_NONE,
0,
{0, 0, 0, 0}
};
handler.processRequest(request);
auto response = handler.getResponse();
EXPECT_EQ(response.result, franklyboot::msg::RES_OK);
// Additional assertions...
}cmake -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS="-g -O0" ..-
Message Protocol Issues:
- Enable verbose logging in test utilities
- Use hex dumps to inspect raw message bytes
- Validate endianness and byte order
-
Flash Operation Problems:
- Use device simulator with debug output
- Check address calculations and bounds
- Verify CRC implementations
-
Template Parameter Issues:
- Review static assertions in handler.h
- Validate memory layout calculations
- Check for overflow in address arithmetic
// Debug message printing (in test environment)
void debugPrintMsg(const franklyboot::msg::Msg& msg) {
printf("Request: 0x%04X, Result: 0x%02X, PacketID: %d\n",
msg.request, msg.result, msg.packet_id);
printf("Data: 0x%02X 0x%02X 0x%02X 0x%02X\n",
msg.data[0], msg.data[1], msg.data[2], msg.data[3]);
}
// Memory dump utility
void debugDumpFlash(uint32_t start, uint32_t size) {
for (uint32_t i = 0; i < size; i += 16) {
printf("%08X: ", start + i);
for (uint32_t j = 0; j < 16 && i + j < size; ++j) {
printf("%02X ", hwi::readByteFromFlash(start + i + j));
}
printf("\n");
}
}The project includes CI configuration for automated testing:
- Build Verification: Multiple compiler versions
- Test Execution: Full test suite on each commit
- Code Quality: Formatting and static analysis checks
- Documentation: Automated documentation generation
- All tests must pass
- Code coverage minimum threshold
- No static analysis warnings
- Documentation must be updated for API changes
- Stack Usage: Handler uses minimal stack space
- RAM Requirements: Only page buffer and message structures
- Flash Usage: Template instantiation creates single binary
- Response Time: Deterministic response generation
- Flash Operations: Hardware-dependent timing
- CRC Calculations: Linear time complexity
- Template Specialization: Optimize for common configurations
- Inlining: Critical path functions should be inlined
- Memory Access: Minimize flash reads during operation
- Error Paths: Fast failure for invalid requests