pebble/tests/libutil/test_circular_buffer.c

285 lines
11 KiB
C
Raw Permalink Normal View History

/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "util/circular_buffer.h"
#include "clar.h"
#include <string.h>
#include "stubs_passert.h"
#include "stubs_pbl_malloc.h"
void test_circular_buffer__initialize(void) {
}
void test_circular_buffer__cleanup(void) {
}
void test_circular_buffer__circular_buffer(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
const uint8_t* out_buffer;
uint16_t out_length;
// We should start out empty
cl_assert(!circular_buffer_read(&buffer, 1, &out_buffer, &out_length));
cl_assert(circular_buffer_write(&buffer, (uint8_t*) "123", 3));
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 5);
cl_assert(circular_buffer_write(&buffer, (uint8_t*) "456", 3));
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 2);
cl_assert(!circular_buffer_write(&buffer, (uint8_t*) "789", 3)); // too big
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 2);
cl_assert(circular_buffer_read(&buffer, 4, &out_buffer, &out_length));
cl_assert_equal_i(out_length, 4);
cl_assert(memcmp(out_buffer, "1234", 4) == 0);
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 2);
cl_assert(circular_buffer_consume(&buffer, 4));
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 6);
// Now there's just 56 in the buffer. Fill it to the brim
cl_assert(circular_buffer_write(&buffer, (uint8_t*) "789", 3));
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 3);
cl_assert(circular_buffer_write(&buffer, (uint8_t*) "abc", 3));
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 0);
cl_assert(!circular_buffer_write(&buffer, (uint8_t*) "d", 1)); // too full
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 0);
// Try a wrapped read
cl_assert(circular_buffer_read(&buffer, 6, &out_buffer, &out_length));
cl_assert_equal_i(out_length, 4);
cl_assert(memcmp(out_buffer, (uint8_t*) "5678", 4) == 0);
cl_assert(circular_buffer_consume(&buffer, 4));
// Get the rest of the wrapped read
cl_assert(circular_buffer_read(&buffer, 2, &out_buffer, &out_length));
cl_assert_equal_i(out_length, 2);
cl_assert(memcmp(out_buffer, (uint8_t*) "9a", 2) == 0);
cl_assert(circular_buffer_consume(&buffer, 2));
// Consume one without reading it
cl_assert(circular_buffer_consume(&buffer, 1));
// Read the last little bit
cl_assert(circular_buffer_read(&buffer, 1, &out_buffer, &out_length));
cl_assert_equal_i(out_length, 1);
cl_assert(memcmp(out_buffer, (uint8_t*) "c", 1) == 0);
cl_assert(circular_buffer_consume(&buffer, 1));
// And we should be empty
cl_assert(!circular_buffer_read(&buffer, 1, &out_buffer, &out_length));
cl_assert(!circular_buffer_consume(&buffer, 1));
}
void test_circular_buffer__copy(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
const uint16_t data_out_size = 8;
uint8_t data_out[data_out_size];
// Test copy when there is nothing in the buffer:
cl_assert_equal_i(circular_buffer_copy(&buffer, data_out, data_out_size), 0);
// Write + consume, so read index is at 2:
circular_buffer_write(&buffer, (uint8_t *)"0123", 4);
circular_buffer_consume(&buffer, 2);
// Write data that will be wrapped:
circular_buffer_write(&buffer, (uint8_t *)"456789", 6);
// Test copying the whole thing (providing buffer of 8 bytes):
memset(data_out, 0, data_out_size);
cl_assert_equal_i(circular_buffer_copy(&buffer, data_out, data_out_size), 8);
cl_assert(memcmp("23456789", data_out, 8) == 0);
// Test partial copy (providing buffer of 6 bytes):
memset(data_out, 0, data_out_size);
cl_assert_equal_i(circular_buffer_copy(&buffer, data_out, 6), 6);
cl_assert(memcmp("234567", data_out, 6) == 0);
}
void test_circular_buffer__copy_offset(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
const uint16_t data_out_size = 8;
uint8_t data_out[data_out_size];
// Assert zero bytes copied, empty buffer:
cl_assert_equal_i(circular_buffer_copy_offset(&buffer, 0 /* start_offset */,
data_out, data_out_size), 0);
// Assert zero bytes copied, start offset > storage size:
cl_assert_equal_i(circular_buffer_copy_offset(&buffer, sizeof(storage) + 1 /* start_offset */,
data_out, data_out_size), 0);
// Valid offset, non-wrapping copy:
circular_buffer_write(&buffer, (uint8_t *)"0123", 4);
cl_assert_equal_i(circular_buffer_copy_offset(&buffer, 3 /* start_offset */,
data_out, data_out_size), 1);
cl_assert(memcmp("3", data_out, 1) == 0);
// Offset as long as the available data:
cl_assert_equal_i(circular_buffer_copy_offset(&buffer, 4 /* start_offset */,
data_out, data_out_size), 0);
// Free up 2 bytes at the beginning:
circular_buffer_consume(&buffer, 2);
// Write data that will be wrapped:
cl_assert_equal_b(circular_buffer_write(&buffer, (uint8_t *)"456789", 6), true);
cl_assert_equal_i(circular_buffer_copy_offset(&buffer, 2 /* start_offset */,
data_out, data_out_size), 6);
cl_assert(memcmp("456789", data_out, 6) == 0);
}
void test_circular_buffer__direct_write(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
circular_buffer_write(&buffer, (uint8_t *)"0123", 4);
uint8_t *data_out;
uint16_t contiguous_num_bytes_left = circular_buffer_write_prepare(&buffer, &data_out);
cl_assert_equal_i(contiguous_num_bytes_left, 4);
memcpy(data_out, "456", 3);
circular_buffer_write_finish(&buffer, 3);
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 1);
cl_assert_equal_i(circular_buffer_get_read_space_remaining(&buffer), 7);
contiguous_num_bytes_left = circular_buffer_write_prepare(&buffer, &data_out);
cl_assert_equal_i(contiguous_num_bytes_left, 1);
memcpy(data_out, "7", 1);
circular_buffer_write_finish(&buffer, 1);
cl_assert_equal_i(circular_buffer_get_write_space_remaining(&buffer), 0);
cl_assert_equal_i(circular_buffer_get_read_space_remaining(&buffer), 8);
contiguous_num_bytes_left = circular_buffer_write_prepare(&buffer, &data_out);
cl_assert_equal_i(contiguous_num_bytes_left, 0);
cl_assert_equal_p(data_out, NULL);
const uint16_t copy_out_size = 8;
uint8_t copy_out[copy_out_size];
cl_assert_equal_i(circular_buffer_copy(&buffer, copy_out, copy_out_size), 8);
cl_assert_equal_i(memcmp(copy_out, "01234567", 8), 0);
circular_buffer_consume(&buffer, 2);
cl_assert_equal_i(circular_buffer_copy(&buffer, copy_out, copy_out_size), 6);
cl_assert_equal_i(memcmp(copy_out, "234567", 6), 0);
contiguous_num_bytes_left = circular_buffer_write_prepare(&buffer, &data_out);
cl_assert_equal_i(contiguous_num_bytes_left, 2);
memcpy(data_out, "AB", 2);
circular_buffer_write_finish(&buffer, 2);
cl_assert_equal_i(circular_buffer_copy(&buffer, copy_out, copy_out_size), 8);
cl_assert_equal_i(memcmp(copy_out, "234567AB", 8), 0);
contiguous_num_bytes_left = circular_buffer_write_prepare(&buffer, &data_out);
cl_assert_equal_i(contiguous_num_bytes_left, 0);
cl_assert_equal_p(data_out, NULL);
}
void test_circular_buffer__read_or_copy_returns_false_when_length_is_too_long(void) {
CircularBuffer buffer;
uint8_t storage[1];
circular_buffer_init(&buffer, storage, sizeof(storage));
uint8_t *data_out = NULL;
bool caller_should_free = false;
cl_assert_equal_b(false, circular_buffer_read_or_copy(&buffer, &data_out, sizeof(storage) + 1,
malloc, &caller_should_free));
}
void test_circular_buffer__read_or_copy_doesnt_copy_when_already_continguously_stored(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
circular_buffer_write(&buffer, (uint8_t *)"01234567", sizeof(storage));
uint8_t *data_out = NULL;
bool caller_should_free = true;
cl_assert_equal_b(true, circular_buffer_read_or_copy(&buffer, &data_out, sizeof(storage),
malloc, &caller_should_free));
cl_assert_equal_b(false, caller_should_free);
cl_assert_equal_p(data_out, storage);
}
static void *prv_oom_malloc(size_t length) {
return NULL;
}
void test_circular_buffer__read_or_copy_does_copy_when_not_continguously_stored(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
circular_buffer_write(&buffer, (uint8_t *)"01234567", sizeof(storage));
circular_buffer_consume(&buffer, 1);
circular_buffer_write(&buffer, (uint8_t *)"8", 1);
uint8_t *data_out = NULL;
bool caller_should_free = false;
cl_assert_equal_b(true, circular_buffer_read_or_copy(&buffer, &data_out, sizeof(storage),
malloc, &caller_should_free));
cl_assert_equal_b(true, caller_should_free);
cl_assert_equal_m(data_out, "12345678", sizeof(storage));
free(data_out);
// Test OOM scenario:
cl_assert_equal_b(false, circular_buffer_read_or_copy(&buffer, &data_out, sizeof(storage),
prv_oom_malloc, &caller_should_free));
cl_assert_equal_p(data_out, NULL);
cl_assert_equal_b(false, caller_should_free);
}
void test_circular_buffer__read_while_write_pending(void) {
CircularBuffer buffer;
uint8_t storage[8];
circular_buffer_init(&buffer, storage, sizeof(storage));
uint8_t letterA = 'A';
cl_assert(circular_buffer_write(&buffer, &letterA, sizeof(letterA)));
uint8_t *data_buf;
uint16_t num_bytes = circular_buffer_write_prepare(&buffer, &data_buf);
cl_assert_equal_i(sizeof(storage) - sizeof(letterA), num_bytes);
uint8_t letterB = 'B';
data_buf[0] = letterB;
cl_assert(circular_buffer_read(
&buffer, sizeof(letterA), (const uint8_t **)&data_buf, &num_bytes));
cl_assert_equal_i(num_bytes, sizeof(letterA));
cl_assert_equal_m(data_buf, &letterA, sizeof(letterA));
cl_assert(circular_buffer_consume(&buffer, sizeof(letterA)));
circular_buffer_write_finish(&buffer, sizeof(letterB));
cl_assert(circular_buffer_read(
&buffer, sizeof(letterB), (const uint8_t **)&data_buf, &num_bytes));
cl_assert_equal_i(num_bytes, sizeof(letterB));
cl_assert_equal_m(data_buf, &letterB, sizeof(letterB));
}