mirror of
https://github.com/google/pebble.git
synced 2025-03-15 16:51:21 +00:00
285 lines
11 KiB
C
285 lines
11 KiB
C
|
/*
|
||
|
* 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));
|
||
|
}
|