#include "hostlink/hostlink_codec.h" #include "hostlink/sensitive_memory.h" #include #include #include #include #include namespace hostlink { constexpr uint32_t MALLOC_CAP_SPIRAM = 1, MALLOC_CAP_INTERNAL = 2, MALLOC_CAP_8BIT = 4; constexpr int pdPASS = 1; struct TxItem { uint8_t* data = nullptr; size_t len = 0; }; TxItem queued; void* s_tx_queue = &queued; using QueueHandle_t = void*; std::map allocation_sizes; bool full = false, ready = true, fail_allocation = false; unsigned allocations = 0, frees = 0; int s_session; bool is_ready(int) { return ready; } uint16_t next_seq() { return 17; } void* heap_caps_malloc_prefer(size_t size, size_t count, ...) { assert(count == 2); va_list args; va_start(args, count); assert(va_arg(args, uint32_t) == (MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT)); assert(va_arg(args, uint32_t) == (MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT)); va_end(args); if (fail_allocation) return nullptr; ++allocations; auto* value = std::malloc(size); allocation_sizes[value] = size; return value; } void test_free(void* value) { if (value) { const auto size = allocation_sizes.at(value); for (size_t i = 0; i < size; ++i) assert(static_cast(value)[i] == 0); allocation_sizes.erase(value); ++frees; } std::free(value); } int xQueueSend(void*, const TxItem* item, unsigned) { if (full) return 0; queued = *item; full = true; return pdPASS; } int xQueueReceive(void*, TxItem* item, unsigned) { if (!full) return 0; *item = queued; full = false; return pdPASS; } #define free test_free #include "hostlink_tx_actual.inc" #undef free } // namespace hostlink int main() { using namespace hostlink; uint8_t source[kMaxFrameLen]; std::memset(source, 42, sizeof(source)); assert(enqueue_event(0x21, source, sizeof(source), false, 123)); assert(full && allocations == 1 && !frees && queued.len == kMaxFrameLen + kHeaderSize + kCrcSize); Decoder decoder; decoder.push(queued.data, queued.len); Frame frame; assert(decoder.next(frame) && frame.type == 0x21 && frame.seq == 123 && frame.payload.size() == sizeof(source) && !std::memcmp(frame.payload.data(), source, sizeof(source))); const auto* original = queued.data; assert(!enqueue_event(0x82, source, 1, false, 0)); assert(queued.data == original && frees == 1); assert(enqueue_event(0x21, source, 1, true, 124)); assert(queued.data != original && frees == 2); fail_allocation = true; assert(!enqueue_event(0x21, source, 1, true, 0) && frees == 2); fail_allocation = false; ready = false; assert(!enqueue_event(0x21, source, 1, false, 0) && allocations == 3); ready = true; assert(!enqueue_event(0x21, nullptr, 1, false, 0) && allocations == 3); assert(!enqueue_event(0x21, source, kMaxFrameLen + 1, false, 0) && allocations == 3); TxItem final; assert(xQueueReceive(s_tx_queue, &final, 0) == pdPASS); release_tx_item(final); assert(!final.data && !final.len); assert(enqueue_event(0x21, source, 96, false, 125)); ready = false; drain_tx_queue(s_tx_queue); assert(!full && allocations == frees); drain_tx_queue(s_tx_queue); drain_tx_queue(nullptr); assert(allocations == frees); }