/** * @file tests/can_callback.cpp * @brief brief * @date Feb 10, 2016 * @author jjacobs * @copyright 2016 Dual Inventive Technology Centre B.V. * * descr */ #include #include #include #include #include "tests/buffer.h" extern "C" { #include "config.c" } // Common test setup for buffer, callbacks, items #define TEST_CONFIG_SETUP(bufferSize) \ uint8_t buf_data[bufferSize]; \ struct di_buffer buf; \ struct di_config_ctx conf; \ di_buffer_init(&buf, buf_data, bufferSize); \ memset(buf_data, 0x55, sizeof(buf_data)); \ di_config_init(&conf); \ di_config_set_items(&conf, items, DI_ARRAY_SIZE(items)); \ di_config_set_size(&conf, sizeof(buf_data)); \ di_config_set_private_data(&conf, &buf); \ di_config_set_read(&conf, &read_cb); \ di_config_set_write(&conf, &write_cb); /** Unit test configuration item uids */ enum item_uids { ITEM_TOKEN = 1, ITEM_ACTIVATION = 2, ITEM_STRING = 3 }; #define ITEM_TOKEN_DEFAULT 0x5f5f5f5f /** Unit test configuration items list */ static const struct di_config_item items[] { { ITEM_TOKEN, sizeof(uint32_t), DI_CONFIG_ITEM_DEFAULT_UINT32(ITEM_TOKEN_DEFAULT) }, { ITEM_ACTIVATION, sizeof(bool), DI_CONFIG_ITEM_DEFAULT_TYPE_BOOL, { 0 } }, { ITEM_STRING, 32, DI_CONFIG_ITEM_DEFAULT_STR("deadbeef") } }; /** Lowlevel configuration driver to read from a di_buffer */ di_errno_t read_cb(struct di_config_ctx *ctx, uint32_t offset, void *data, size_t len) { memcpy(data, ((struct di_buffer *)ctx->private_data)->data + offset, len); return DNOK; } /** Lowlevel configuration driver to write into a di_buffer */ di_errno_t write_cb(struct di_config_ctx *ctx, uint32_t offset, const void *data, size_t len) { di_buffer_memcpy((struct di_buffer *)ctx->private_data, offset, data, len); return DNOK; } /** * Check if initialisation of a item list with duplicates unsets the configuration context * and returns a error code. */ TEST(config, set_items_duplicate_uid) { struct di_config_ctx conf; static struct di_config_item itemsWithDup[4] { { 1, sizeof(uint32_t), DI_CONFIG_ITEM_DEFAULT_TYPE_UINT32, { 0 } }, { 2, sizeof(uint32_t), DI_CONFIG_ITEM_DEFAULT_TYPE_UINT32, { 0 } }, { 1, sizeof(bool), DI_CONFIG_ITEM_DEFAULT_TYPE_BOOL, { 0 } }, { 2, sizeof(bool), DI_CONFIG_ITEM_DEFAULT_TYPE_BOOL, { 0 } } }; di_config_init(&conf); // Initialize with correct config item list EXPECT_EQ(DNOK, di_config_set_items(&conf, items, DI_ARRAY_SIZE(items))); EXPECT_EQ(items, conf.items.begin); EXPECT_EQ(DI_ARRAY_SIZE(items), conf.items.size); // Try to initialize with item list with duplicates, this will reset the conf->items array EXPECT_EQ(DNE_PARAM, di_config_set_items(&conf, itemsWithDup, DI_ARRAY_SIZE(itemsWithDup))); EXPECT_EQ(nullptr, conf.items.begin); EXPECT_EQ(0U, conf.items.size); } /** * Test writing 4 lowlevel blobs and check if CRC16 CCIT and buffer is correct */ TEST(config, write) { TEST_CONFIG_SETUP(64); di_buffer_flush(&buf); // Flush buffer to zero, then we can use string compare // Write offset (keep 2 byte crc offset in mind...), blob, size // We use the ITEM_TOKEN because its size is 4 bytes, no fill is appended EXPECT_EQ(DNOK, di_config_write(&conf, ITEM_TOKEN, 0, "1234", 4)); EXPECT_EQ(DNOK, di_config_write(&conf, ITEM_TOKEN, 6, "5678", 4)); EXPECT_EQ(DNOK, di_config_write(&conf, ITEM_TOKEN, 12, "9ABC", 4)); EXPECT_EQ(DNOK, di_config_write(&conf, ITEM_TOKEN, 18, "DEF0", 4)); EXPECT_STREQ("\x49\x53""1234" "\x30\x48""5678" "\xca\x62""9ABC" "\xc9\x47""DEF0", (const char *)buf_data); test_buffer_dump(&buf); } /** Check if correct byte offset is calculated for the items */ TEST(config, uid_get_offset) { uint32_t offset; TEST_CONFIG_SETUP(64); /* ITEM_TOKEN is located at offset: 0 */ EXPECT_EQ(DNOK, di_config_uid_get_offset(&conf, ITEM_TOKEN, &offset)); EXPECT_EQ(0U, offset); /* ITEM_ACTIVATION is located at offset: DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(uint32_t) */ EXPECT_EQ(DNOK, di_config_uid_get_offset(&conf, ITEM_ACTIVATION, &offset)); EXPECT_EQ(DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(uint32_t), offset); /* ITEM_STRING is located at offset: * * ITEM_TOKEN: DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(uint32_t) + * * ITEM_ACTIVATION: DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(bool) */ EXPECT_EQ(DNOK, di_config_uid_get_offset(&conf, ITEM_STRING, &offset)); EXPECT_EQ(DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(bool) + DI_CONFIG_CRC_CCIT16_OFFSET + sizeof(uint32_t), offset); } /** Set/get ITEM_ACTIVATION boolean */ TEST(config, set_get_bool_activation) { TEST_CONFIG_SETUP(32); // Set bool val_bool = true; EXPECT_EQ(DNOK, di_config_set(&conf, ITEM_ACTIVATION, val_bool)); // Get val_bool = false; EXPECT_EQ(DNOK, di_config_get(&conf, ITEM_ACTIVATION, &val_bool)); EXPECT_EQ(true, val_bool); test_buffer_dump(&buf); } /** Set/get ITEM_TOKEN */ TEST(config, set_get_u32_token) { TEST_CONFIG_SETUP(32); // Set uint32_t val_u32 = 0xAABBCCDD; EXPECT_EQ(DNOK, di_config_set(&conf, ITEM_TOKEN, val_u32)); // Get val_u32 = 0; EXPECT_EQ(DNOK, di_config_get(&conf, ITEM_TOKEN, &val_u32)); EXPECT_EQ(0xAABBCCDD, val_u32); test_buffer_dump(&buf); } /** Try to write more data than the configuration item TOKEN can hold (write u64 while max item size is u32) */ TEST(config, set_u32_token_overflow_with_u64) { TEST_CONFIG_SETUP(32); // Set fails because item is u32 and action is u64 uint64_t val_u64 = 0xABABABABABABABAB; EXPECT_EQ(DNE_RANGE, di_config_set(&conf, ITEM_TOKEN, val_u64)); // Get, this fails due to invalid size. Item is u32 action is u64 val_u64 = 0; EXPECT_EQ(DNE_RANGE, di_config_get(&conf, ITEM_TOKEN, &val_u64)); EXPECT_EQ(0U, val_u64); test_buffer_dump(&buf); } /** * Set and get string * 1. Set string (const char *), which is smaller than the item size (32byte) * 2. Get string, buffer is the same size as the item size! */ TEST(config, set_get_string) { TEST_CONFIG_SETUP(64); // Set const char *val_str = "foo-bar-baz"; EXPECT_EQ(DNOK, di_config_set(&conf, ITEM_STRING, val_str)); // Get char val_str_buf[32]; // Same size as ITEM_STRING size ! memset(val_str_buf, 0xab, sizeof(val_str_buf)); EXPECT_EQ(DNOK, di_config_get_string(&conf, ITEM_STRING, val_str_buf, sizeof(val_str_buf))); EXPECT_STREQ(val_str, val_str_buf); test_buffer_dump(&buf); } /** * Set string default value and check if get returns correct */ TEST(config, set_default_get_string) { TEST_CONFIG_SETUP(64); // Set default EXPECT_EQ(DNOK, di_config_set_default(&conf, ITEM_STRING)); // Get string char val_str_buf[32]; // Same size as ITEM_STRING size ! memset(val_str_buf, 0, sizeof(val_str_buf)); EXPECT_EQ(DNOK, di_config_get_string(&conf, ITEM_STRING, val_str_buf, sizeof(val_str_buf))); EXPECT_STREQ("deadbeef", val_str_buf); test_buffer_dump(&buf); } /** * Get or set default string value */ TEST(config, get_or_set_default_string) { TEST_CONFIG_SETUP(64); char val_str_buf[32]; // Same size as ITEM_STRING size ! memset(val_str_buf, 0, sizeof(val_str_buf)); // Get (unwritten) EXPECT_EQ(DNE_CHECKSUM, di_config_get_string(&conf, ITEM_STRING, val_str_buf, sizeof(val_str_buf))); // Get or set default EXPECT_EQ(DNOK, di_config_get_or_load_default_string(&conf, ITEM_STRING, val_str_buf, sizeof(val_str_buf))); test_buffer_dump(&buf); // Get EXPECT_EQ(DNOK, di_config_get_string(&conf, ITEM_STRING, val_str_buf, sizeof(val_str_buf))); EXPECT_STREQ("deadbeef", val_str_buf); test_buffer_dump(&buf); } /** * Check if set and get return DNE_NOTFOUND when uid is not known */ TEST(config, uid_not_found) { TEST_CONFIG_SETUP(64); uint32_t val = 666; EXPECT_EQ(DNE_NOTFOUND, di_config_set(&conf, 1234, val)); EXPECT_EQ(DNE_NOTFOUND, di_config_get(&conf, 1234, &val)); } /** * Check if read or write is not set the operations return DNE_OPNOTSUPP */ TEST(config, set_get_operation_not_supported) { TEST_CONFIG_SETUP(64); di_config_set_read(&conf, NULL); di_config_set_write(&conf, NULL); uint32_t val = 666; EXPECT_EQ(DNE_OPNOTSUPP, di_config_set(&conf, ITEM_TOKEN, val)); EXPECT_EQ(DNE_OPNOTSUPP, di_config_get(&conf, ITEM_TOKEN, &val)); } /** * Check if lowlevel buffer is to small the operation is denied with DNE_RANGE */ TEST(config, lowlevel_size_to_small) { TEST_CONFIG_SETUP(4); uint32_t val = 666; EXPECT_EQ(DNE_RANGE, di_config_set(&conf, ITEM_TOKEN, val)); EXPECT_EQ(DNE_RANGE, di_config_get(&conf, ITEM_TOKEN, &val)); } /** * Check if default value is correctly saved and returned to the application * 1. Write token with manual value * 2. Corrupt token CRC * 3. Try to get corrupt token, check for error * 4. Get token and load default */ TEST(config, load_default) { TEST_CONFIG_SETUP(32); di_buffer_flush(&buf); // Flush buffer to zero, then we can use string compare // Set token uint32_t val = 666; EXPECT_EQ(DNOK, di_config_set(&conf, ITEM_TOKEN, val)); // Corrupt crc buf_data[0] = 0xaa; // Try to get corrupt value val = 0; EXPECT_EQ(DNE_CHECKSUM, di_config_get(&conf, ITEM_TOKEN, &val)); // Load "default" value from macro EXPECT_EQ(DNOK, di_config_get_or_load_default(&conf, ITEM_TOKEN, &val)); EXPECT_EQ(ITEM_TOKEN_DEFAULT, val); // Check buffer is filled as we expect // String: "____", CRC-CCIT16: 0xe271 EXPECT_STREQ("\x71\xe2\x5f\x5f\x5f\x5f", (const char *)buf_data); test_buffer_dump(&buf); } /** * Check if default u32 value is read from the config item */ TEST(config, get_default_u32) { TEST_CONFIG_SETUP(32); di_buffer_flush(&buf); // Flush buffer to zero, then we can use string compare // Get default token value uint32_t val_u32 = 0; EXPECT_EQ(DNOK, di_config_get_default(&conf, ITEM_TOKEN, &val_u32)); EXPECT_EQ(ITEM_TOKEN_DEFAULT, val_u32); } /** * Check if default string value is read from the config item */ TEST(config, get_default_string) { TEST_CONFIG_SETUP(32); di_buffer_flush(&buf); // Flush buffer to zero, then we can use string compare // Get default string value char val_str[16]; memset(val_str, 0, sizeof(val_str)); EXPECT_EQ(DNOK, di_config_get_default_string(&conf, ITEM_STRING, val_str, sizeof(val_str))); EXPECT_STREQ("deadbeef",(const char *)val_str); // Check if to small buffer returns an error and doesn't write anything memset(val_str, 0, sizeof(val_str)); }