diff options
author | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-04 18:27:40 +0200 |
---|---|---|
committer | Loek Le Blansch <loek@pipeframe.xyz> | 2024-06-04 18:27:40 +0200 |
commit | 078c6661c24a9460240d9c7c063a44e9bed6f96a (patch) | |
tree | 4d19d628210d5e0414228f1330c0d998b44c02e8 | |
parent | 18d06c79b9f6a625eb218a15c8216556fb99dc02 (diff) |
add i2ctcp unit tests
-rw-r--r-- | client/makefile | 2 | ||||
-rw-r--r-- | i2ctcp/i2ctcpv1.c | 41 | ||||
-rw-r--r-- | shared/pb/moddrv.c | 21 | ||||
-rw-r--r-- | shared/pb/moddrv.h | 2 | ||||
-rw-r--r-- | test/CMakeLists.txt | 27 | ||||
-rw-r--r-- | test/ExampleTest.cpp | 5 | ||||
-rw-r--r-- | test/i2ctcp/main.cpp | 46 | ||||
-rw-r--r-- | test/makefile | 7 |
8 files changed, 94 insertions, 57 deletions
diff --git a/client/makefile b/client/makefile index 8352615..5cbf045 100644 --- a/client/makefile +++ b/client/makefile @@ -1,2 +1,4 @@ +TARGET = $(BUILD_DIR)/pbc + include ../lazy.mk diff --git a/i2ctcp/i2ctcpv1.c b/i2ctcp/i2ctcpv1.c index b406d8d..2231038 100644 --- a/i2ctcp/i2ctcpv1.c +++ b/i2ctcp/i2ctcpv1.c @@ -7,38 +7,31 @@ #include "i2ctcpv1.h" int i2ctcp_read(i2ctcp_msg_t * target, const char * buf, size_t buf_sz) { + mpack_reader_t reader; + mpack_reader_init_data(&reader, buf, buf_sz); + // at start of message if (target->_rdata == 0) { - // NOTE: The entire start of a message needs to be readable from the buffer - // at this point. When target->addr can be read and target->length is past - // the end of the current buffer block, this function will crash and burn. - // This is a highly unlikely scenario, as i2ctcp_read is called for each - // chunk of a TCP frame, and frames (should) include only one puzzle bus - // message. The check here is kind of optional. - if (buf_sz < 4) return -1; - - // mpack reader is used for the first buffer block, as it contains the data - // size info - mpack_reader_t reader; - mpack_reader_init_data(&reader, buf, buf_sz); - target->addr = mpack_expect_u16(&reader); target->length = target->_rdata = mpack_expect_bin(&reader); + if (mpack_reader_error(&reader) != mpack_ok) return -1; target->data = (char *) malloc(target->length); - // read remaining data in (header) packet - size_t to_read = mpack_reader_remaining(&reader, NULL); - mpack_read_bytes(&reader, target->data, to_read); - target->_rdata -= to_read; - } else { - // continue reading chunks of target->data until the amount of bytes - // specified in target->length - size_t to_read = MIN(buf_sz, target->_rdata); - char * data = target->data + target->length - target->_rdata; - memcpy(data, buf, to_read); - target->_rdata -= to_read; + // seek forward in buf to where binary data begins (to avoid having to read + // from private member reader.data in the memcpy below) + buf += buf_sz - mpack_reader_remaining(&reader, NULL); } + // continue reading chunks of target->data until the amount of bytes + // specified in target->length + size_t to_read = MIN(mpack_reader_remaining(&reader, NULL), target->_rdata); + char * data = target->data + target->length - target->_rdata; + memcpy(data, buf, to_read); + target->_rdata -= to_read; + // NOTE: memcpy is used here because mpack_read_bytes requires that a tag was + // opened, which is not the case for the chunks following the initial mpack + // header + // if rdata = 0, the message was completely read return target->_rdata; } diff --git a/shared/pb/moddrv.c b/shared/pb/moddrv.c index 1f7fab8..9677341 100644 --- a/shared/pb/moddrv.c +++ b/shared/pb/moddrv.c @@ -17,25 +17,8 @@ __weak void pbdrv_hook_mod_state_write(enum pb_state state) { _global_state = state; } -__weak void pbdrv_i2c_recv(uint16_t i2c_addr, const char * buf, size_t sz) { - if (sz == 0) return; - enum pb_cmd cmd = (enum pb_cmd) buf[0]; - - // shift buffer pointer to only contain the puzzle bus message buf - buf++; - sz--; - - // allow user to implement custom commands - if (pbdrv_hook_cmd(i2c_addr, cmd, buf, sz)) - return; - - switch (cmd) { - case PB_CMD_READ: return pbdrv_handle_read(i2c_addr, buf, sz); - case PB_CMD_WRITE: return pbdrv_handle_write(i2c_addr, buf, sz); - case PB_CMD_MAGIC: return pbdrv_handle_magic(i2c_addr, buf, sz); - case PB_CMD_SEX: return pbdrv_handle_sex(i2c_addr, buf, sz); - default: return; - } +__weak void pbdrv_i2c_recv(const char * buf, size_t sz) { + return; } __weak void pbdrv_handle_read(uint16_t i2c_addr, const char * buf, size_t sz) { diff --git a/shared/pb/moddrv.h b/shared/pb/moddrv.h index ecfc13a..d2e2d97 100644 --- a/shared/pb/moddrv.h +++ b/shared/pb/moddrv.h @@ -24,7 +24,7 @@ extern "C" { #endif -void pbdrv_i2c_recv(uint16_t i2c_addr, const char * buf, size_t sz); +void pbdrv_i2c_recv(const char * buf, size_t sz); void pbdrv_i2c_send(uint16_t i2c_addr, const char * buf, size_t sz); enum pb_state pbdrv_hook_mod_state_read(); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a280a86..44191cc 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -1,23 +1,26 @@ cmake_minimum_required(VERSION 3.29) -project(puzzlebox_test C CXX ASM) - set(CMAKE_C_STANDARD 11) set(CMAKE_CXX_STANDARD 17) set(CMAKE_EXPORT_COMPILE_COMMANDS 1) -add_executable(tests - ExampleTest.cpp -) +project(pbtest C CXX ASM) -enable_testing() +include(../i2ctcp/include.cmake) +include(../shared/include.cmake) + +add_executable(test + ExampleTest.cpp + i2ctcp/main.cpp + ) +# enable_testing() add_subdirectory(lib/googletest) -target_include_directories(tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}) -target_link_libraries(tests PRIVATE gtest_main) +# target_include_directories(tests PRIVATE ${CMAKE_CURRENT_LIST_DIR}) +target_link_libraries(test + gtest_main + i2ctcp + mpack + ) -add_test( - NAME tests - COMMAND tests -) diff --git a/test/ExampleTest.cpp b/test/ExampleTest.cpp index a3909f5..3da58ff 100644 --- a/test/ExampleTest.cpp +++ b/test/ExampleTest.cpp @@ -4,4 +4,7 @@ class ExampleTest : public testing::Test { protected: }; -TEST_F(ExampleTest, Test) { EXPECT_EQ(5, 5); }
\ No newline at end of file +TEST_F(ExampleTest, Test) { + EXPECT_EQ(5, 5); +} + diff --git a/test/i2ctcp/main.cpp b/test/i2ctcp/main.cpp new file mode 100644 index 0000000..1f0c3ff --- /dev/null +++ b/test/i2ctcp/main.cpp @@ -0,0 +1,46 @@ +#include <algorithm> +#include <gtest/gtest.h> + +#include "i2ctcpv1.h" + +using std::min; + +const uint8_t data[] = { 0xff, 0x00, 0xde, 0xad, 0xbe, 0xef, }; +const size_t data_len = sizeof(data); +const size_t chunk_size = 6; + +char * send_data = nullptr; +size_t send_size = 0; + +TEST(i2ctcp, send) { + i2ctcp_msg_t send_msg = { + .addr = 0x1122, + .data = (char *) data, + .length = data_len, + }; + + ASSERT_TRUE(i2ctcp_write(&send_msg, &send_data, &send_size)); + ASSERT_NE(send_data, nullptr); + ASSERT_GE(send_size, 0); +} + +TEST(i2ctcp, recv) { + i2ctcp_msg_t recv_msg; + i2ctcp_read_reset(&recv_msg); + for (size_t i = 0; i < send_size; i += chunk_size) { + size_t expected_size = min(send_size, i + chunk_size) - i; + + int parsed = i2ctcp_read(&recv_msg, send_data + i, expected_size); + EXPECT_GE(parsed, 0); + + if (i + expected_size == send_size) + EXPECT_EQ(parsed, 0); + else + EXPECT_GT(parsed, 0); + } + + ASSERT_NE(recv_msg.data, nullptr); + ASSERT_EQ(recv_msg.length, data_len); + ASSERT_EQ(0, memcmp(recv_msg.data, data, data_len)); +} + diff --git a/test/makefile b/test/makefile new file mode 100644 index 0000000..7aeee34 --- /dev/null +++ b/test/makefile @@ -0,0 +1,7 @@ +TARGET = $(BUILD_DIR)/test + +include ../lazy.mk + +test: $(TARGET) FORCE + $(TARGET) + |