blob: b6e39c1f5638e3d09f0a886d85305d5b9bd506ff [file]
//! @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);
}
}
}