#include #include #include "tests/buffer.h" extern "C" { #include "rpc/lowlevel.c" } #define TEST_DI_RPC_LL_MSG_DATA_SIZE 64 DI_BUFFER_DECL(buf1, TEST_DI_RPC_LL_MSG_DATA_SIZE); DI_BUFFER_DECL(buf2, TEST_DI_RPC_LL_MSG_DATA_SIZE); /** * Verify if memory copy of remaining data from di_rpc_ll_msg into di_buffer works * 1. Write two messages into two di_buffers * 2. Concat second message into buffer of first message * 3. Decode buffer, verify first message is correct and the buffer is flagged to have data remaining * 4. Copy remaining data from di_rpc_ll_msg into di_buffer * 5. Decode second message from di_buffer * 6. Verify message is correctly decoded */ TEST(rpc_ll_memcpy_remaining, two_packets_single_buf) { struct di_rpc_ll_msg msg; const size_t msg1_size = sizeof("AAAA"); const size_t msg2_size = sizeof("BBBBBBBB"); /* Initialize buffer for msg1 */ di_buffer_init(&buf1, buf1_data, sizeof(buf1_data)); di_buffer_flush(&buf1); /* Initialize buffer for msg2 */ di_buffer_init(&buf2, buf2_data, sizeof(buf2_data)); di_buffer_flush(&buf2); /* Write first message */ di_rpc_ll_write_header(&buf1, DI_RPC_LL_MSG_TYPE_PLAIN, msg1_size); ASSERT_EQ(DNOK, di_rpc_ll_write_data(&buf1, (const uint8_t *)"AAAA", msg1_size)); /* Write second message */ di_rpc_ll_write_header(&buf2, DI_RPC_LL_MSG_TYPE_REPLY, msg2_size); ASSERT_EQ(DNOK, di_rpc_ll_write_data(&buf2, (const uint8_t *)"BBBBBBBB", msg2_size)); /* Concat msg2 buffer to msg1 buffer */ ASSERT_EQ(DNOK, di_buffer_append(&buf1, &buf2)); di_buffer_flush(&buf2); /* Decode message 1 */ ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, di_rpc_ll_decode(&buf1, &msg)); ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, msg.status); ASSERT_EQ(DI_RPC_LL_MSG_HDR_SIZE + msg2_size, msg.remaining); /* Remaining bytes HEADER + msg2_size */ ASSERT_EQ(DI_RPC_LL_MSG_TYPE_PLAIN, msg.type); ASSERT_EQ(msg1_size, msg.size); ASSERT_STREQ("AAAA", (const char *)msg.data); /* Memcpy remaining message 2 to start of empty buf1 */ ASSERT_EQ(DNOK, di_rpc_ll_memcpy_remaining(&buf2, &msg)); /* Decode message 2 */ ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, di_rpc_ll_decode(&buf2, &msg)); ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, msg.status); ASSERT_EQ(DI_RPC_LL_MSG_TYPE_REPLY, msg.type); ASSERT_EQ(DI_RPC_LL_MSG_REPLY_UNKNOWN, msg.reply); ASSERT_EQ(msg2_size, msg.size); ASSERT_STREQ("BBBBBBBB", (const char *)msg.data); } /** * Verify the memory copy operation is not supported if there is no data remaining after decode */ TEST(rpc_ll_memcpy, DNE_OPNOTSUPP) { struct di_rpc_ll_msg msg; di_buffer_init(&buf1, buf1_data, sizeof(buf1_data)); di_buffer_flush(&buf1); di_rpc_ll_write_header(&buf1, DI_RPC_LL_MSG_TYPE_REPLY, DI_RPC_LL_MSG_REPLY_MKAY_SIZE); ASSERT_EQ(DNOK, di_rpc_ll_write_data(&buf1, (const uint8_t *)DI_RPC_LL_MSG_REPLY_MKAY, DI_RPC_LL_MSG_REPLY_MKAY_SIZE)); ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, di_rpc_ll_decode(&buf1, &msg)); ASSERT_EQ(DNE_OPNOTSUPP, di_rpc_ll_memcpy_remaining(&buf2, &msg)); } /** * Verify the memory copy operation will not copy to dst when the buffer is to small */ TEST(rpc_ll_memcpy, DNE_NOMEM) { struct di_rpc_ll_msg msg; di_buffer_init(&buf1, buf1_data, sizeof(buf1_data)); di_buffer_flush(&buf1); di_rpc_ll_write_header(&buf1, DI_RPC_LL_MSG_TYPE_REPLY, DI_RPC_LL_MSG_REPLY_MKAY_SIZE); ASSERT_EQ(DNOK, di_rpc_ll_write_data(&buf1, (const uint8_t *)DI_RPC_LL_MSG_REPLY_MKAY, DI_RPC_LL_MSG_REPLY_MKAY_SIZE)); test_buffer_dump(&buf1); ASSERT_EQ(DNOK, di_buffer_append(&buf1, &buf1)); ASSERT_EQ(DI_RPC_LL_MSG_STAT_OK, di_rpc_ll_decode(&buf1, &msg)); /* Fake buf2 is 8 bytes */ buf2.size = 8; ASSERT_EQ(DNE_NOMEM, di_rpc_ll_memcpy_remaining(&buf2, &msg)); buf2.size = TEST_DI_RPC_LL_MSG_DATA_SIZE; } /** * Check if writing a lowlevel header into a to small buffer (DI_RPC_LL_MSG_HDR_SIZE - 1) * results in a DNE_NOMEM. */ TEST(rpc_ll_write_header, out_of_memory) { di_buffer_init(&buf1, buf1_data, sizeof(buf1_data)); di_buffer_flush(&buf1); /* Check buf1.size < DI_RPC_LL_MSG_TYPE_REPLY */ buf1.size = DI_RPC_LL_MSG_HDR_SIZE - 1; ASSERT_EQ(DNE_NOMEM, di_rpc_ll_write_header(&buf1, DI_RPC_LL_MSG_TYPE_TIME, 0)); /* Check buf1.size < (DI_RPC_LL_MSG_HDR_SIZE + len) tries to write 5 bytes as payload in the header but the buffer only fits 4 bytes payload */ buf1.size = DI_RPC_LL_MSG_HDR_SIZE + 4; ASSERT_EQ(DNE_NOMEM, di_rpc_ll_write_header(&buf1, DI_RPC_LL_MSG_TYPE_TIME, 5)); } /** * Verify if writing more than 2^16-1 is not allowed and results in DNE_NOMEM * This because the lowlevel messages are limited to uint16_t * @note The assumption is made first the lengths are checked, then the src and dst pointers */ TEST(rpc_ll, DNE_NOMEM) { ASSERT_EQ(DNE_NOMEM, di_rpc_ll_write_header(NULL, DI_RPC_LL_MSG_TYPE_PLAIN, UINT16_MAX + 1)); ASSERT_EQ(DNE_NOMEM, di_rpc_ll_write_data(NULL, NULL, UINT16_MAX + 1)); }