| //! @file |
| //! |
| |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "CppUTest/MemoryLeakDetectorMallocMacros.h" |
| #include "CppUTest/MemoryLeakDetectorNewMacros.h" |
| #include "CppUTest/TestHarness.h" |
| #include "CppUTestExt/MockSupport.h" |
| #include "memfault/config.h" |
| #include "memfault/core/compact_log_serializer.h" |
| |
| extern "C" { |
| // emulated linker symbol expected by the serializer |
| extern uint32_t __start_log_fmt; |
| uint32_t __start_log_fmt; |
| |
| static void prv_write_cb(void *ctx, uint32_t offset, const void *buf, size_t buf_len) { |
| CHECK(ctx != NULL); |
| uint8_t *result_buf = (uint8_t *)ctx; |
| memcpy(&result_buf[offset], buf, buf_len); |
| } |
| } |
| |
| TEST_GROUP(MfltCompactLog) { |
| void setup() { } |
| |
| void teardown() { |
| mock().checkExpectations(); |
| mock().clear(); |
| } |
| }; |
| |
| static uint32_t prv_get_fake_log_id(void) { |
| // We'll just force all our log ids to be the same for test purposes. We just want to verify that |
| // its computed relative to the "__start_log_fmt" linker symbol |
| return (uint32_t)(uintptr_t)&__start_log_fmt + 0xA; |
| } |
| |
| static char *prv_setup_encoder(sMemfaultCborEncoder *encoder, size_t expected_size) { |
| char *buf = (char *)calloc(expected_size, 1); |
| memfault_cbor_encoder_init(encoder, prv_write_cb, buf, expected_size); |
| return buf; |
| } |
| |
| static void prv_check_result(sMemfaultCborEncoder *encoder, char *result, const void *expected_buf, |
| size_t expected_buf_len) { |
| const size_t encoded_length = memfault_cbor_encoder_deinit(encoder); |
| LONGS_EQUAL(expected_buf_len, encoded_length); |
| MEMCMP_EQUAL(expected_buf, result, expected_buf_len); |
| free(result); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_NoArg) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { 0x81, 0x0A }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| char *result_buf = prv_setup_encoder(&encoder, expected_seq_len); |
| |
| const uint32_t compressed_fmt = 1; // no args |
| memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), compressed_fmt); |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_Int32) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { 0x82, 0x0A, 0xB }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| char *result_buf = prv_setup_encoder(&encoder, expected_seq_len); |
| |
| const uint32_t compressed_fmt = 0x4; // 0b100 |
| const bool success = |
| memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), compressed_fmt, 11); |
| CHECK(success); |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_Int64) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { |
| 0x82, 0x0A, 0x81, 0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, 0xa5, 0x10, 0x00 |
| }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| char *result_buf = prv_setup_encoder(&encoder, expected_seq_len); |
| |
| const uint32_t compressed_fmt = 0x5; // 0b101 |
| const int64_t bigint = 1000000000000; |
| const bool success = |
| memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), compressed_fmt, bigint); |
| CHECK(success); |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_Double) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { 0x82, 0x0A, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, 0x75, 0x9c }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| char *result_buf = prv_setup_encoder(&encoder, expected_seq_len); |
| |
| const uint32_t compressed_fmt = 0x6; // 0b110 |
| const double a_double = 1.0e+300; |
| const bool success = |
| memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), compressed_fmt, a_double); |
| CHECK(success); |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_String) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { 0x82, 0x0A, 0x65, 'h', 'e', 'l', 'l', 'o' }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| char *result_buf = prv_setup_encoder(&encoder, expected_seq_len); |
| |
| const uint32_t compressed_fmt = 0x7; // 0b111 |
| const char *str_arg = "hello"; |
| const bool success = |
| memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), compressed_fmt, str_arg); |
| CHECK(success); |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_StringTooLong) { |
| sMemfaultCborEncoder encoder; |
| #define OVERLONG_STRING \ |
| "This is a very long string that is intended to make the compact log " \ |
| "serialization exceed the maximum allowed log size for testing purposes." |
| static_assert(sizeof(OVERLONG_STRING) - 1 > MEMFAULT_LOG_MAX_LINE_SAVE_LEN, |
| "Test string is not long enough to trigger truncation"); |
| |
| char *result_buf = prv_setup_encoder(&encoder, MEMFAULT_LOG_MAX_LINE_SAVE_LEN); |
| |
| const uint32_t compressed_fmt = 0x7; // 0b111 |
| const bool success = memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), |
| compressed_fmt, OVERLONG_STRING); |
| free(result_buf); |
| CHECK(success == false); |
| int status = memfault_cbor_encoder_get_status(&encoder); |
| LONGS_EQUAL(MEMFAULT_CBOR_ENCODER_STATUS_ENOMEM, status); |
| } |
| |
| TEST(MfltCompactLog, Test_MfltCompactLog_MultiArg) { |
| sMemfaultCborEncoder encoder; |
| |
| uint8_t expected_seq[] = { 0x85, 0x0A, 0xB, 0x81, 0x1b, 0x00, 0x00, 0x00, 0xe8, 0xd4, |
| 0xa5, 0x10, 0x00, 0xfb, 0x7e, 0x37, 0xe4, 0x3c, 0x88, 0x00, |
| 0x75, 0x9c, 0x65, 'h', 'e', 'l', 'l', 'o' }; |
| const size_t expected_seq_len = sizeof(expected_seq); |
| |
| const uint32_t compressed_fmt = 0x11B; // 0b1.0001.1011 |
| |
| for (size_t i = 0; i <= expected_seq_len; i++) { |
| char *result_buf = prv_setup_encoder(&encoder, i); |
| |
| // all together |
| const uint8_t hhx = 11; |
| const int64_t lld = 1000000000000; |
| const double g = 1.0e+300; |
| const char *str_arg = "hello"; |
| const bool success = memfault_log_compact_serialize(&encoder, prv_get_fake_log_id(), |
| compressed_fmt, hhx, lld, g, str_arg); |
| const bool success_expected = (i == expected_seq_len); |
| CHECK(success == success_expected); |
| if (success) { |
| prv_check_result(&encoder, result_buf, expected_seq, expected_seq_len); |
| } else { |
| free(result_buf); |
| } |
| } |
| } |