mirror of
https://github.com/google/pebble.git
synced 2025-08-24 20:17:26 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
90
tests/fw/util/test_base64.c
Normal file
90
tests/fw/util/test_base64.c
Normal file
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* 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/base64.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include "stubs_passert.h"
|
||||
|
||||
|
||||
// Stubs
|
||||
///////////////////////////////////////////////////////////
|
||||
int g_pbl_log_level = 0;
|
||||
void pbl_log(const char* src_filename, int src_line_number, const char* fmt, ...) { }
|
||||
|
||||
// Tests
|
||||
///////////////////////////////////////////////////////////
|
||||
static void prv_test_decode_encode(const char* test_name, char* buffer, unsigned int buffer_length,
|
||||
const uint8_t* expected, unsigned int expected_length) {
|
||||
cl_assert(buffer_length % 4 == 0);
|
||||
|
||||
char original_in[buffer_length + 1];
|
||||
memcpy(original_in, buffer, buffer_length + 1);
|
||||
|
||||
// test decode
|
||||
unsigned int num_bytes = base64_decode_inplace(buffer, buffer_length);
|
||||
cl_assert(num_bytes == expected_length);
|
||||
cl_assert(memcmp(buffer, expected, num_bytes) == 0);
|
||||
|
||||
// test encode
|
||||
char out[buffer_length + 1];
|
||||
int result = base64_encode(out, buffer_length + 1, expected, expected_length);
|
||||
cl_assert_equal_i(result, buffer_length);
|
||||
cl_assert_equal_m(out, original_in, buffer_length);
|
||||
}
|
||||
|
||||
void test_base64__initialize(void) {
|
||||
}
|
||||
|
||||
void test_base64__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_base64__decode(void) {
|
||||
{
|
||||
char buffer[] = "abcd";
|
||||
const uint8_t expected[] = { 0x69, 0xb7, 0x1d };
|
||||
prv_test_decode_encode("basic", buffer, 4, expected, 3);
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[] = "ABCD";
|
||||
const uint8_t expected[] = { 0x0, 0x10, 0x83 };
|
||||
prv_test_decode_encode("upper", buffer, 4, expected, 3);
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[] = "abcdABCD";
|
||||
const uint8_t expected[] = { 0x69, 0xb7, 0x1d, 0x0, 0x10, 0x83 };
|
||||
prv_test_decode_encode("twobyte", buffer, 8, expected, 6);
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[] = "vu8=";
|
||||
const uint8_t expected[] = { 0xbe, 0xef };
|
||||
prv_test_decode_encode("1pad", buffer, 4, expected, 2);
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[] = "aQ==";
|
||||
const uint8_t expected[] = { 0x69 };
|
||||
prv_test_decode_encode("2pad", buffer, 4, expected, 1);
|
||||
}
|
||||
}
|
132
tests/fw/util/test_buffer.c
Normal file
132
tests/fw/util/test_buffer.c
Normal file
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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/buffer.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
static const char* test_data = "This is a very complicated case, Maude.";
|
||||
|
||||
void test_buffer__should_add_data_until_full(void) {
|
||||
const size_t buffer_size = 101;
|
||||
|
||||
Buffer* b = buffer_create(buffer_size);
|
||||
|
||||
int bytes_written = 0;
|
||||
int num_elements = buffer_size / sizeof(test_data);
|
||||
for (int i = 0; i < num_elements; ++i) {
|
||||
cl_assert_equal_i(b->bytes_written, i * sizeof(test_data));
|
||||
cl_assert_equal_i(buffer_get_bytes_remaining(b), buffer_size - (i * sizeof(test_data)));
|
||||
bytes_written += buffer_add(b, (uint8_t *) test_data, sizeof(test_data));
|
||||
cl_assert_equal_i(bytes_written, (i + 1) * sizeof(test_data));
|
||||
cl_assert_equal_i(buffer_get_bytes_remaining(b), buffer_size - ((i+1) * sizeof(test_data)));
|
||||
}
|
||||
|
||||
cl_assert(buffer_get_bytes_remaining(b) > 0);
|
||||
bytes_written = buffer_add(b, (uint8_t *) test_data, sizeof(test_data));
|
||||
cl_assert_equal_i(bytes_written, 0);
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
void test_buffer__cannot_remove_beyond_written(void) {
|
||||
Buffer *b = buffer_create(5);
|
||||
cl_assert_equal_i(0, buffer_remove(b, 0, 0));
|
||||
cl_assert_passert(buffer_remove(b, 0, 1));
|
||||
|
||||
uint8_t b1 = 1;
|
||||
buffer_add(b, &b1, sizeof(uint8_t));
|
||||
cl_assert_passert(buffer_remove(b, 0, 2));
|
||||
cl_assert_equal_i(1, b->bytes_written);
|
||||
|
||||
cl_assert_equal_i(1, buffer_remove(b, 0, 1));
|
||||
cl_assert_equal_i(0, b->bytes_written);
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
void test_buffer__can_remove(void) {
|
||||
uint8_t b1 = 1;
|
||||
uint8_t b2 = 2;
|
||||
uint8_t b3 = 3;
|
||||
uint8_t b4 = 4;
|
||||
|
||||
Buffer *b = buffer_create(5);
|
||||
// works on empty buffer
|
||||
cl_assert_equal_i(0, buffer_remove(b, 0, 0));
|
||||
|
||||
buffer_add(b, &b1, sizeof(uint8_t));
|
||||
buffer_add(b, &b2, sizeof(uint8_t));
|
||||
buffer_add(b, &b3, sizeof(uint8_t));
|
||||
buffer_add(b, &b4, sizeof(uint8_t));
|
||||
|
||||
// handles out of bounds cases
|
||||
cl_assert_passert(buffer_remove(b, 0, 5));
|
||||
cl_assert_passert(buffer_remove(b, 1, 4));
|
||||
|
||||
cl_assert_equal_i(4, b->bytes_written);
|
||||
cl_assert_equal_i(b->data[0], b1);
|
||||
cl_assert_equal_i(b->data[1], b2);
|
||||
cl_assert_equal_i(b->data[2], b3);
|
||||
cl_assert_equal_i(b->data[3], b4);
|
||||
|
||||
// moves removed remaining bytes to close the gap
|
||||
cl_assert_equal_i(2, buffer_remove(b, 1*sizeof(uint8_t), 2*sizeof(uint8_t)));
|
||||
cl_assert_equal_i(2, b->bytes_written);
|
||||
cl_assert_equal_i(b->data[0], b1);
|
||||
cl_assert_equal_i(b->data[1], b4);
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
void test_buffer__can_remove_interior_data(void) {
|
||||
uint8_t b1 = 1;
|
||||
uint8_t b2 = 2;
|
||||
uint8_t b3 = 3;
|
||||
uint8_t b4 = 4;
|
||||
|
||||
Buffer *b = buffer_create(4);
|
||||
buffer_add(b, &b1, sizeof(uint8_t));
|
||||
buffer_add(b, &b2, sizeof(uint8_t));
|
||||
buffer_add(b, &b3, sizeof(uint8_t));
|
||||
buffer_add(b, &b4, sizeof(uint8_t));
|
||||
|
||||
// removing second element shifts elements three and four to overwrite it
|
||||
cl_assert_equal_i(sizeof(uint8_t), buffer_remove(b, 1 * sizeof(uint8_t), sizeof(uint8_t)));
|
||||
cl_assert_equal_i(b->bytes_written, 3);
|
||||
cl_assert_equal_i(b->data[0], b1);
|
||||
cl_assert_equal_i(b->data[1], b3);
|
||||
cl_assert_equal_i(b->data[2], b4);
|
||||
|
||||
free(b);
|
||||
}
|
||||
|
||||
void test_buffer__can_read_and_write_uint32(void) {
|
||||
uint32_t expected = 0x12345678;
|
||||
|
||||
Buffer *b = buffer_create(4);
|
||||
|
||||
buffer_add(b, (const uint8_t* const)&expected, sizeof(expected));
|
||||
cl_assert_equal_i(expected, *(uint32_t*)b->data);
|
||||
|
||||
free(b);
|
||||
}
|
393
tests/fw/util/test_dict.c
Normal file
393
tests/fw/util/test_dict.c
Normal file
|
@ -0,0 +1,393 @@
|
|||
/*
|
||||
* 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/dict.h"
|
||||
#include "util/math.h"
|
||||
#include "util/net.h"
|
||||
#include "util/size.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <strings.h>
|
||||
|
||||
// Stubs
|
||||
///////////////////////////////////////////////////////////
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
|
||||
// Tests
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
void test_dict__initialize(void) {
|
||||
}
|
||||
|
||||
void test_dict__cleanup(void) {
|
||||
}
|
||||
|
||||
static const uint32_t SOME_DATA_KEY = 0xb00bf00b;
|
||||
static const uint8_t SOME_DATA[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
|
||||
|
||||
static const uint32_t SOME_STRING_KEY = 0xbeefbabe;
|
||||
static const char *SOME_STRING = "Hello World";
|
||||
|
||||
static const uint32_t SOME_NULL_KEY = 0x0;
|
||||
|
||||
static const uint32_t SOME_EMPTY_STRING_KEY = 0x1;
|
||||
static const char *SOME_EMPTY_STRING = "";
|
||||
|
||||
static const uint32_t SOME_UINT8_KEY = 0x88888888;
|
||||
static const uint32_t SOME_UINT16_KEY = 0x16161616;
|
||||
static const uint32_t SOME_UINT32_KEY = 0x32323232;
|
||||
static const uint32_t SOME_INT8_KEY = 0x11888888;
|
||||
static const uint32_t SOME_INT16_KEY = 0x11161616;
|
||||
static const uint32_t SOME_INT32_KEY = 0x11323232;
|
||||
|
||||
void test_dict__calc_size(void) {
|
||||
uint32_t size;
|
||||
size = dict_calc_buffer_size(0);
|
||||
cl_assert(size == sizeof(Dictionary));
|
||||
size = dict_calc_buffer_size(1, 1);
|
||||
cl_assert(size == sizeof(Dictionary) + sizeof(Tuple) + 1);
|
||||
size = dict_calc_buffer_size(3, 10, 100, 1000);
|
||||
cl_assert(size == sizeof(Dictionary) + (3 * sizeof(Tuple)) + 10 + 100 + 1000);
|
||||
}
|
||||
|
||||
struct SerializeTestResult {
|
||||
bool okay;
|
||||
uint16_t expected_size;
|
||||
};
|
||||
|
||||
static void serialize_callback(const uint8_t * const data, const uint16_t size, void *context) {
|
||||
struct SerializeTestResult *result = context;
|
||||
result->okay = true;
|
||||
result->expected_size = size;
|
||||
|
||||
// Read back:
|
||||
DictionaryIterator iter;
|
||||
Tuple *tuple = dict_read_begin_from_buffer(&iter, data, size);
|
||||
cl_assert(tuple != NULL);
|
||||
cl_assert(iter.dictionary->count == 3);
|
||||
}
|
||||
|
||||
void test_dict__tuplets_utils(void) {
|
||||
Tuplet tuplets[] = {
|
||||
TupletBytes(SOME_DATA_KEY, SOME_DATA, sizeof(SOME_DATA)),
|
||||
TupletCString(SOME_STRING_KEY, SOME_STRING),
|
||||
TupletInteger(SOME_UINT32_KEY, (uint32_t) 32),
|
||||
};
|
||||
const uint32_t size = dict_calc_buffer_size_from_tuplets(tuplets, 3);
|
||||
cl_assert(size == sizeof(Dictionary) + (3 * sizeof(Tuple)) + sizeof(SOME_DATA) + strlen(SOME_STRING) + 1 + sizeof(uint32_t));
|
||||
|
||||
struct SerializeTestResult context = { .okay = false, .expected_size = size };
|
||||
DictionaryResult result = dict_serialize_tuplets(serialize_callback, &context,
|
||||
tuplets, 3);
|
||||
cl_assert(result == DICT_OK);
|
||||
cl_assert(context.okay == true);
|
||||
cl_assert(context.expected_size == size);
|
||||
}
|
||||
|
||||
void test_dict__write_read(void) {
|
||||
// Stack allocated buffer:
|
||||
const uint8_t key_count = 10;
|
||||
const uint32_t size = dict_calc_buffer_size(key_count,
|
||||
sizeof(SOME_DATA),
|
||||
strlen(SOME_STRING) + 1,
|
||||
sizeof(uint8_t),
|
||||
sizeof(uint16_t),
|
||||
sizeof(uint32_t),
|
||||
sizeof(int8_t),
|
||||
sizeof(int16_t),
|
||||
sizeof(int32_t),
|
||||
0,
|
||||
strlen(SOME_EMPTY_STRING) + 1);
|
||||
const uint32_t surplus = 16; // allocate more than needed, see comment with the `final_size` test
|
||||
uint8_t buffer[size + surplus];
|
||||
|
||||
// Write:
|
||||
DictionaryIterator iter;
|
||||
DictionaryResult result;
|
||||
result = dict_write_begin(&iter, buffer, sizeof(buffer));
|
||||
cl_assert(result == DICT_OK);
|
||||
|
||||
result = dict_write_data(&iter, SOME_DATA_KEY, SOME_DATA, sizeof(SOME_DATA));
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_cstring(&iter, SOME_STRING_KEY, SOME_STRING);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_uint8(&iter, SOME_UINT8_KEY, 8);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_uint16(&iter, SOME_UINT16_KEY, 16);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_uint32(&iter, SOME_UINT32_KEY, 32);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_int8(&iter, SOME_INT8_KEY, -8);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_int16(&iter, SOME_INT16_KEY, -16);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_int32(&iter, SOME_INT32_KEY, -32);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_cstring(&iter, SOME_NULL_KEY, NULL);
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_cstring(&iter, SOME_EMPTY_STRING_KEY, SOME_EMPTY_STRING);
|
||||
cl_assert(result == DICT_OK);
|
||||
|
||||
const uint32_t final_size = dict_write_end(&iter);
|
||||
cl_assert(result == DICT_OK);
|
||||
cl_assert(final_size == size);
|
||||
cl_assert(iter.dictionary->count == key_count);
|
||||
|
||||
// Read:
|
||||
Tuple *tuple = dict_read_begin_from_buffer(&iter, buffer, final_size);
|
||||
uint8_t count = 0;
|
||||
bool data_found = false;
|
||||
bool string_found = false;
|
||||
bool uint8_found = false;
|
||||
bool uint16_found = false;
|
||||
bool uint32_found = false;
|
||||
bool int8_found = false;
|
||||
bool int16_found = false;
|
||||
bool int32_found = false;
|
||||
bool null_cstring_found = false;
|
||||
bool empty_cstring_found = false;
|
||||
while (tuple != NULL) {
|
||||
++count;
|
||||
switch (tuple->key) {
|
||||
case SOME_DATA_KEY:
|
||||
cl_assert(tuple->length == sizeof(SOME_DATA));
|
||||
cl_assert(memcmp(tuple->value->data, SOME_DATA, sizeof(SOME_DATA)) == 0);
|
||||
data_found = true;
|
||||
break;
|
||||
case SOME_STRING_KEY:
|
||||
cl_assert(tuple->length == strlen(SOME_STRING) + 1);
|
||||
cl_assert(strncmp(tuple->value->cstring, SOME_STRING, strlen(SOME_STRING) + 1) == 0);
|
||||
// Check zero termination:
|
||||
cl_assert(tuple->value->cstring[strlen(SOME_STRING)] == 0);
|
||||
string_found = true;
|
||||
break;
|
||||
case SOME_UINT8_KEY:
|
||||
cl_assert(tuple->length == sizeof(uint8_t));
|
||||
cl_assert(tuple->value->uint8 == 8);
|
||||
uint8_found = true;
|
||||
break;
|
||||
case SOME_UINT16_KEY:
|
||||
cl_assert(tuple->length == sizeof(uint16_t));
|
||||
cl_assert(tuple->value->uint16 == 16);
|
||||
uint16_found = true;
|
||||
break;
|
||||
case SOME_UINT32_KEY:
|
||||
cl_assert(tuple->length == sizeof(uint32_t));
|
||||
cl_assert(tuple->value->uint32 == 32);
|
||||
uint32_found = true;
|
||||
break;
|
||||
case SOME_INT8_KEY:
|
||||
cl_assert(tuple->length == sizeof(int8_t));
|
||||
cl_assert(tuple->value->int8 == -8);
|
||||
int8_found = true;
|
||||
break;
|
||||
case SOME_INT16_KEY:
|
||||
cl_assert(tuple->length == sizeof(int16_t));
|
||||
cl_assert(tuple->value->int16 == -16);
|
||||
int16_found = true;
|
||||
break;
|
||||
case SOME_INT32_KEY:
|
||||
cl_assert(tuple->length == sizeof(int32_t));
|
||||
cl_assert(tuple->value->int32 == -32);
|
||||
int32_found = true;
|
||||
break;
|
||||
case SOME_NULL_KEY:
|
||||
cl_assert(tuple->length == 0);
|
||||
null_cstring_found = true;
|
||||
break;
|
||||
case SOME_EMPTY_STRING_KEY:
|
||||
cl_assert(tuple->length == strlen(SOME_EMPTY_STRING) + 1);
|
||||
cl_assert(strncmp(tuple->value->cstring, SOME_EMPTY_STRING, strlen(SOME_EMPTY_STRING) + 1) == 0);
|
||||
// Check zero termination:
|
||||
cl_assert(tuple->value->cstring[strlen(SOME_EMPTY_STRING)] == 0);
|
||||
empty_cstring_found = true;
|
||||
break;
|
||||
}
|
||||
tuple = dict_read_next(&iter);
|
||||
}
|
||||
cl_assert(count == key_count);
|
||||
cl_assert(data_found);
|
||||
cl_assert(string_found);
|
||||
cl_assert(uint8_found);
|
||||
cl_assert(uint16_found);
|
||||
cl_assert(uint32_found);
|
||||
cl_assert(int8_found);
|
||||
cl_assert(int16_found);
|
||||
cl_assert(int32_found);
|
||||
cl_assert(null_cstring_found);
|
||||
cl_assert(empty_cstring_found);
|
||||
}
|
||||
|
||||
void test_dict__out_of_storage(void) {
|
||||
uint8_t buffer[1];
|
||||
DictionaryIterator iter;
|
||||
DictionaryResult result;
|
||||
result = dict_write_begin(&iter, buffer, 0);
|
||||
cl_assert(result == DICT_NOT_ENOUGH_STORAGE);
|
||||
result = dict_write_begin(&iter, buffer, sizeof(buffer));
|
||||
cl_assert(result == DICT_OK);
|
||||
result = dict_write_cstring(&iter, SOME_STRING_KEY, SOME_STRING);
|
||||
cl_assert(result == DICT_NOT_ENOUGH_STORAGE);
|
||||
}
|
||||
|
||||
void test_dict__tuple_header_size(void) {
|
||||
Tuple t;
|
||||
t.type = 0;
|
||||
t.type = ~t.type;
|
||||
uint8_t num_bits = ffs(t.type + 1) - 1;
|
||||
cl_assert(num_bits % 8 == 0);
|
||||
// Test that the .value field isn't part of the header:
|
||||
cl_assert(sizeof(Tuple) == sizeof(t.key) + sizeof(t.length) + (num_bits / 8));
|
||||
}
|
||||
|
||||
static void *CONTEXT = (void *)0xabcdabcd;
|
||||
static const char *NEW_STRING = "Bye, bye, World";
|
||||
static bool is_int8_updated = false;
|
||||
static bool is_string_updated = false;
|
||||
static bool should_update_existing_keys_only = false;
|
||||
static bool test_not_enough_storage = false;
|
||||
static bool is_data_updated = false;
|
||||
|
||||
static void update_key_callback(const uint32_t key, const Tuple *new_tuple, const Tuple *old_tuple, void *context) {
|
||||
cl_assert(CONTEXT == context);
|
||||
switch (key) {
|
||||
case SOME_INT8_KEY:
|
||||
is_int8_updated = true;
|
||||
cl_assert(should_update_existing_keys_only == false);
|
||||
cl_assert(new_tuple->type == TUPLE_INT);
|
||||
cl_assert(new_tuple->length == sizeof(int8_t));
|
||||
cl_assert(new_tuple->value->int8 == -3);
|
||||
cl_assert(old_tuple == NULL_TUPLE);
|
||||
break;
|
||||
case SOME_STRING_KEY:
|
||||
is_string_updated = true;
|
||||
cl_assert(new_tuple->type == TUPLE_CSTRING);
|
||||
cl_assert(new_tuple->length == strlen(NEW_STRING) + 1);
|
||||
cl_assert(strcmp(new_tuple->value->cstring, NEW_STRING) == 0);
|
||||
cl_assert(old_tuple->type == TUPLE_CSTRING);
|
||||
cl_assert(old_tuple->length == strlen(SOME_STRING) + 1);
|
||||
cl_assert(strcmp(old_tuple->value->cstring, SOME_STRING) == 0);
|
||||
break;
|
||||
case SOME_DATA_KEY:
|
||||
is_data_updated = true;
|
||||
cl_assert(new_tuple->type == TUPLE_BYTE_ARRAY);
|
||||
cl_assert(new_tuple->length == sizeof(SOME_DATA));
|
||||
cl_assert(old_tuple->type == TUPLE_BYTE_ARRAY);
|
||||
cl_assert(old_tuple->length == sizeof(SOME_DATA));
|
||||
cl_assert(memcmp(new_tuple->value->data, old_tuple->value->data, sizeof(SOME_DATA)) == 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void test_dict__merge(void) {
|
||||
Tuplet dest_tuplets[] = {
|
||||
TupletBytes(SOME_DATA_KEY, SOME_DATA, sizeof(SOME_DATA)), // unchanged value
|
||||
TupletCString(SOME_STRING_KEY, SOME_STRING),
|
||||
};
|
||||
Tuplet source_tuplets[] = {
|
||||
TupletCString(SOME_STRING_KEY, NEW_STRING),
|
||||
TupletInteger(SOME_INT8_KEY, (int8_t) -3),
|
||||
};
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
is_int8_updated = false;
|
||||
is_string_updated = false;
|
||||
is_data_updated = false;
|
||||
|
||||
test_not_enough_storage = (i == 2);
|
||||
should_update_existing_keys_only = (i == 0) || test_not_enough_storage;
|
||||
|
||||
uint32_t tmp_size = 0;
|
||||
const uint32_t source_size = dict_calc_buffer_size_from_tuplets(source_tuplets, ARRAY_LENGTH(source_tuplets));
|
||||
const uint32_t min_dest_size = dict_calc_buffer_size_from_tuplets(dest_tuplets, ARRAY_LENGTH(dest_tuplets));
|
||||
|
||||
const uint32_t dest_size = test_not_enough_storage ? min_dest_size : min_dest_size + source_size;
|
||||
|
||||
uint8_t source_buffer[source_size];
|
||||
tmp_size = source_size; // dict_serialize_tuplets_to_buffer modifies this.
|
||||
dict_serialize_tuplets_to_buffer(source_tuplets, ARRAY_LENGTH(source_tuplets), source_buffer, &tmp_size);
|
||||
DictionaryIterator source_iter;
|
||||
dict_read_begin_from_buffer(&source_iter, source_buffer, source_size);
|
||||
|
||||
uint8_t dest_buffer[dest_size];
|
||||
tmp_size = dest_size; // dict_serialize_tuplets_to_buffer modifies this.
|
||||
dict_serialize_tuplets_to_buffer(dest_tuplets, ARRAY_LENGTH(dest_tuplets), dest_buffer, &tmp_size);
|
||||
DictionaryIterator dest_iter;
|
||||
dict_read_begin_from_buffer(&dest_iter, dest_buffer, dest_size);
|
||||
|
||||
tmp_size = dest_size;
|
||||
dict_merge(&dest_iter, &tmp_size, &source_iter, should_update_existing_keys_only, update_key_callback, (void *) CONTEXT);
|
||||
cl_assert(is_int8_updated == !should_update_existing_keys_only);
|
||||
cl_assert(is_string_updated == !test_not_enough_storage);
|
||||
cl_assert(is_data_updated == !test_not_enough_storage);
|
||||
|
||||
enum {
|
||||
INT8_IDX,
|
||||
STRING_IDX,
|
||||
DATA_IDX,
|
||||
NUM_TUPLES,
|
||||
};
|
||||
bool has_tuple[NUM_TUPLES] = { false, false, false };
|
||||
Tuple *tuple = dict_read_begin_from_buffer(&dest_iter, dest_buffer, tmp_size);
|
||||
while (tuple) {
|
||||
switch (tuple->key) {
|
||||
case SOME_DATA_KEY:
|
||||
has_tuple[DATA_IDX] = true;
|
||||
cl_assert(tuple->type == TUPLE_BYTE_ARRAY);
|
||||
cl_assert(tuple->length == sizeof(SOME_DATA));
|
||||
cl_assert(memcmp(tuple->value->data, SOME_DATA, sizeof(SOME_DATA)) == 0);
|
||||
break;
|
||||
case SOME_STRING_KEY:
|
||||
has_tuple[STRING_IDX] = true;
|
||||
cl_assert(tuple->type == TUPLE_CSTRING);
|
||||
if (test_not_enough_storage) {
|
||||
// If there is insufficient storage, we don't expect this tuple to
|
||||
// have been updated (since it can't fit!)
|
||||
cl_assert(tuple->length == strlen(SOME_STRING) + 1);
|
||||
cl_assert(strcmp(tuple->value->cstring, SOME_STRING) == 0);
|
||||
} else {
|
||||
cl_assert(tuple->length == strlen(NEW_STRING) + 1);
|
||||
cl_assert(strcmp(tuple->value->cstring, NEW_STRING) == 0);
|
||||
}
|
||||
break;
|
||||
case SOME_INT8_KEY:
|
||||
has_tuple[INT8_IDX] = true;
|
||||
cl_assert(should_update_existing_keys_only == false);
|
||||
cl_assert(tuple->type == TUPLE_INT);
|
||||
cl_assert(tuple->length == sizeof(int8_t));
|
||||
cl_assert(tuple->value->int8 == -3);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
tuple = dict_read_next(&dest_iter);
|
||||
}
|
||||
if (test_not_enough_storage || should_update_existing_keys_only) {
|
||||
cl_assert(has_tuple[INT8_IDX] == false);
|
||||
} else {
|
||||
cl_assert(has_tuple[INT8_IDX] == true);
|
||||
}
|
||||
cl_assert(has_tuple[STRING_IDX] == true);
|
||||
cl_assert(has_tuple[DATA_IDX] == true);
|
||||
}
|
||||
}
|
209
tests/fw/util/test_generic_attribute.c
Normal file
209
tests/fw/util/test_generic_attribute.c
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "services/normal/voice_endpoint_private.h"
|
||||
|
||||
#include "fake_pebble_tasks.h"
|
||||
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
|
||||
// setup and teardown
|
||||
void test_generic_attribute__initialize(void) {
|
||||
}
|
||||
|
||||
void test_generic_attribute__cleanup(void) {
|
||||
}
|
||||
|
||||
// tests
|
||||
|
||||
void test_generic_attribute__find_attribute(void) {
|
||||
uint8_t data1[] = {
|
||||
0x02, // attribute list - num attributes
|
||||
|
||||
0x02, // attribute type - transcription
|
||||
0x2F, 0x00, // attribute length
|
||||
|
||||
// Transcription
|
||||
0x01, // Transcription type
|
||||
0x02, // Sentence count
|
||||
|
||||
// Sentence #1
|
||||
0x02, 0x00, // Word count
|
||||
|
||||
// Word #1
|
||||
85, // Confidence
|
||||
0x05, 0x00, // Word length
|
||||
'H', 'e', 'l', 'l', 'o',
|
||||
|
||||
// Word #2
|
||||
74, // Confidence
|
||||
0x08, 0x00, // Word length
|
||||
'c', 'o', 'm', 'p', 'u', 't', 'e', 'r',
|
||||
|
||||
// Sentence #2
|
||||
0x03, 0x00, // Word count
|
||||
|
||||
// Word #1
|
||||
13, // Confidence
|
||||
0x04, 0x00, // Word length
|
||||
'h', 'e', 'l', 'l',
|
||||
|
||||
// Word #1
|
||||
3, // Confidence
|
||||
0x02, 0x00, // Word length
|
||||
'o', 'h',
|
||||
|
||||
// Word #2
|
||||
0, // Confidence
|
||||
0x07, 0x00, // Word length
|
||||
'c', 'o', 'm', 'p', 'u', 't', 'a',
|
||||
|
||||
0x03, // attribute type - App UUID
|
||||
0x10, 0x00, // attribute length
|
||||
|
||||
0xa8, 0xc5, 0x63, 0x17, 0xa2, 0x89, 0x46, 0x5c,
|
||||
0xbe, 0xf1, 0x5b, 0x98, 0x0d, 0xfd, 0xb0, 0x8a,
|
||||
};
|
||||
|
||||
// same as data1, but with the attribute order swapped
|
||||
uint8_t data2[] = {
|
||||
0x02, // attribute list - num attributes
|
||||
|
||||
0x03, // attribute type - App UUID
|
||||
0x10, 0x00, // attribute length
|
||||
|
||||
0xa8, 0xc5, 0x63, 0x17, 0xa2, 0x89, 0x46, 0x5c,
|
||||
0xbe, 0xf1, 0x5b, 0x98, 0x0d, 0xfd, 0xb0, 0x8a,
|
||||
|
||||
0x02, // attribute type - transcription
|
||||
0x2F, 0x00, // attribute length
|
||||
|
||||
// Transcription
|
||||
0x01, // Transcription type
|
||||
0x02, // Sentence count
|
||||
|
||||
// Sentence #1
|
||||
0x02, 0x00, // Word count
|
||||
|
||||
// Word #1
|
||||
85, // Confidence
|
||||
0x05, 0x00, // Word length
|
||||
'H', 'e', 'l', 'l', 'o',
|
||||
|
||||
// Word #2
|
||||
74, // Confidence
|
||||
0x08, 0x00, // Word length
|
||||
'c', 'o', 'm', 'p', 'u', 't', 'e', 'r',
|
||||
|
||||
// Sentence #2
|
||||
0x03, 0x00, // Word count
|
||||
|
||||
// Word #1
|
||||
13, // Confidence
|
||||
0x04, 0x00, // Word length
|
||||
'h', 'e', 'l', 'l',
|
||||
|
||||
// Word #1
|
||||
3, // Confidence
|
||||
0x02, 0x00, // Word length
|
||||
'o', 'h',
|
||||
|
||||
// Word #2
|
||||
0, // Confidence
|
||||
0x07, 0x00, // Word length
|
||||
'c', 'o', 'm', 'p', 'u', 't', 'a',
|
||||
};
|
||||
|
||||
GenericAttributeList *attr_list1 = (GenericAttributeList *)data1;
|
||||
GenericAttributeList *attr_list2 = (GenericAttributeList *)data2;
|
||||
|
||||
GenericAttribute *attr1 = generic_attribute_find_attribute(attr_list1, VEAttributeIdTranscription,
|
||||
sizeof(data1));
|
||||
cl_assert(attr1);
|
||||
cl_assert_equal_i(attr1->id, VEAttributeIdTranscription);
|
||||
cl_assert_equal_i(attr1->length, 0x2F);
|
||||
size_t offset = sizeof(GenericAttributeList) + sizeof(GenericAttribute);
|
||||
cl_assert_equal_p(attr1->data, &data1[offset]);
|
||||
|
||||
GenericAttribute *attr2 = generic_attribute_find_attribute(attr_list1, VEAttributeIdAppUuid,
|
||||
sizeof(data1));
|
||||
cl_assert(attr2);
|
||||
cl_assert_equal_i(attr2->id, VEAttributeIdAppUuid);
|
||||
cl_assert_equal_i(attr2->length, 16);
|
||||
offset = sizeof(GenericAttributeList) + sizeof(GenericAttribute) +
|
||||
attr1->length + sizeof(GenericAttribute);
|
||||
cl_assert_equal_p(attr2->data, &data1[offset]);
|
||||
|
||||
attr1 = generic_attribute_find_attribute(attr_list2, VEAttributeIdAppUuid, sizeof(data2));
|
||||
cl_assert(attr1);
|
||||
cl_assert_equal_i(attr1->id, VEAttributeIdAppUuid);
|
||||
cl_assert_equal_i(attr1->length, 16);
|
||||
offset = sizeof(GenericAttributeList) + sizeof(GenericAttribute);
|
||||
cl_assert_equal_p(attr1->data, &data2[offset]);
|
||||
|
||||
attr2 = generic_attribute_find_attribute(attr_list2, VEAttributeIdTranscription, sizeof(data2));
|
||||
cl_assert(attr2);
|
||||
cl_assert_equal_i(attr2->id, VEAttributeIdTranscription);
|
||||
cl_assert_equal_i(attr2->length, 0x2F);
|
||||
offset = sizeof(GenericAttributeList) + sizeof(GenericAttribute) +
|
||||
attr1->length + sizeof(GenericAttribute);
|
||||
cl_assert_equal_p(attr2->data, &data2[offset]);
|
||||
|
||||
GenericAttribute *attr3 = generic_attribute_find_attribute(attr_list1, VEAttributeIdAppUuid,
|
||||
sizeof(data1) - 1);
|
||||
cl_assert(!attr3);
|
||||
|
||||
attr3 = generic_attribute_find_attribute(attr_list1, VEAttributeIdAppUuid,
|
||||
sizeof(data1) - sizeof(Uuid));
|
||||
cl_assert(!attr3);
|
||||
|
||||
attr3 = generic_attribute_find_attribute(attr_list1, VEAttributeIdAppUuid,
|
||||
sizeof(data1) - sizeof(Uuid) - 1);
|
||||
cl_assert(!attr3);
|
||||
}
|
||||
|
||||
void test_generic_attribute__add_attribute(void) {
|
||||
uint8_t data[] = {
|
||||
0x01, 0x55, 0x77, 0x54, 0x47
|
||||
};
|
||||
uint8_t data_out[(2 * sizeof(GenericAttribute)) + sizeof(data) + sizeof(Uuid)];
|
||||
GenericAttribute *next = (GenericAttribute *)data_out;
|
||||
next = generic_attribute_add_attribute(next, VEAttributeIdTranscription, data, sizeof(data));
|
||||
size_t offset = sizeof(GenericAttribute) + sizeof(data);
|
||||
cl_assert_equal_p((uint8_t*)next, &data_out[offset]);
|
||||
GenericAttribute expected = {
|
||||
.id = VEAttributeIdTranscription,
|
||||
.length = sizeof(data)
|
||||
};
|
||||
cl_assert_equal_m(&expected, data_out, sizeof(GenericAttribute));
|
||||
cl_assert_equal_m(&data_out[sizeof(GenericAttribute)], data, sizeof(data));
|
||||
|
||||
Uuid uuid;
|
||||
uuid_generate(&uuid);
|
||||
next = generic_attribute_add_attribute(next, VEAttributeIdAppUuid, &uuid, sizeof(uuid));
|
||||
cl_assert_equal_p((uint8_t*)next, data_out + sizeof(data_out));
|
||||
expected = (GenericAttribute) {
|
||||
.id = VEAttributeIdAppUuid,
|
||||
.length = sizeof(Uuid)
|
||||
};
|
||||
cl_assert_equal_m(&expected, &data_out[offset], sizeof(GenericAttribute));
|
||||
offset += sizeof(GenericAttribute);
|
||||
cl_assert_equal_m(&uuid, &data_out[offset], sizeof(uuid));
|
||||
}
|
54
tests/fw/util/test_graphics.c
Normal file
54
tests/fw/util/test_graphics.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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 <clar.h>
|
||||
|
||||
#include "util/graphics.h"
|
||||
|
||||
// Make sure that row stride, bit depth is all being used correctly.
|
||||
// Really, these are just some simple cases and sanity checks.
|
||||
void test_graphics__raw_image_get_value_for_bitdepth(void) {
|
||||
uint8_t test0[] = { 0b11000000 };
|
||||
uint8_t test1[] = { 0, 0, 0, 0b11000000, 0 };
|
||||
uint8_t test2[] = { 0b11000000, 0b00110000, 0b00001100, 0b00000011 };
|
||||
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 0, 0, 1, 1) == 1);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 7, 0, 1, 1) == 0);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 0, 0, 1, 2) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 0, 0, 1, 4) == 12);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 0, 0, 1, 8) == 192);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 0, 0, 1, 1) == 1);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test0, 1, 0, 1, 1) == 1);
|
||||
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test1, 0, 3, 1, 2) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test1, 0, 3, 1, 1) == 1);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test1, 0, 3, 1, 4) == 12);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test1, 0, 3, 1, 8) == 192);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test1, 4, 1, 2, 2) == 3);
|
||||
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 5, 2, 1, 1) == 1);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 6, 2, 1, 1) == 0);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 5, 0, 2, 2) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 5, 0, 2, 2) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 1, 1, 2, 8) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 0, 1, 3, 8) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 1, 1, 1, 2) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 0, 1, 1, 4) == 3);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 1, 1, 2, 4) == 12);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 0, 1, 1, 8) == 48);
|
||||
cl_assert(raw_image_get_value_for_bitdepth(test2, 3, 0, 4, 8) == 3);
|
||||
}
|
||||
|
180
tests/fw/util/test_hdlc.c
Normal file
180
tests/fw/util/test_hdlc.c
Normal file
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/hdlc.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "stubs_passert.h"
|
||||
|
||||
// Setup
|
||||
|
||||
void test_hdlc__initialize(void) {
|
||||
}
|
||||
|
||||
void test_hdlc__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
|
||||
void test_hdlc__decode_no_special(void) {
|
||||
// without any special characters
|
||||
const char *str = "\x7eThis is a long string without any special characters to be escaped.\x7e";
|
||||
int len = strlen(str);
|
||||
HdlcStreamingContext ctx;
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
for (int i = 0; i < len; i++) {
|
||||
char c = str[i];
|
||||
bool should_store, is_invalid;
|
||||
bool is_complete = hdlc_streaming_decode(&ctx, (uint8_t *)&c, &should_store, &is_invalid);
|
||||
cl_assert(is_invalid == false);
|
||||
if (i == 0 || i == len - 1) {
|
||||
cl_assert(is_complete == true);
|
||||
cl_assert(should_store == false);
|
||||
} else {
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == true);
|
||||
cl_assert(c == str[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test_hdlc__special_characters(void) {
|
||||
// make sure the escape characters haven't changed
|
||||
cl_assert(HDLC_FLAG == 0x7e);
|
||||
cl_assert(HDLC_ESCAPE == 0x7d);
|
||||
cl_assert(HDLC_ESCAPE_MASK == 0x20);
|
||||
}
|
||||
|
||||
void test_hdlc__decode_empty(void) {
|
||||
// consecutive empty frames
|
||||
const uint8_t str[4] = {HDLC_FLAG, HDLC_FLAG, HDLC_FLAG, HDLC_FLAG};
|
||||
HdlcStreamingContext ctx;
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char c = str[i];
|
||||
bool should_store, is_invalid;
|
||||
bool is_complete = hdlc_streaming_decode(&ctx, (uint8_t *)&c, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == true);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == false);
|
||||
}
|
||||
}
|
||||
|
||||
void test_hdlc__decode_invalid(void) {
|
||||
// invalid sequences
|
||||
uint8_t data;
|
||||
bool should_store, is_invalid, is_complete;
|
||||
HdlcStreamingContext ctx;
|
||||
|
||||
// two consecutive escape characters
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
data = HDLC_ESCAPE;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == false);
|
||||
data = HDLC_ESCAPE;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == true);
|
||||
|
||||
// an escape character followed by a flag
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
data = HDLC_ESCAPE;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == false);
|
||||
data = HDLC_FLAG;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == true);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == true);
|
||||
}
|
||||
|
||||
void test_hdlc__decode_escaped_special(void) {
|
||||
// 2 escaped special characters
|
||||
uint8_t data;
|
||||
bool should_store, is_invalid, is_complete;
|
||||
HdlcStreamingContext ctx;
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
|
||||
// escaped escape character
|
||||
data = HDLC_ESCAPE;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == false);
|
||||
data = HDLC_ESCAPE ^ HDLC_ESCAPE_MASK;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == true);
|
||||
cl_assert(is_invalid == false);
|
||||
cl_assert(data == HDLC_ESCAPE);
|
||||
|
||||
// escaped flag
|
||||
data = HDLC_ESCAPE;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(is_invalid == false);
|
||||
data = HDLC_FLAG ^ HDLC_ESCAPE_MASK;
|
||||
is_complete = hdlc_streaming_decode(&ctx, &data, &should_store, &is_invalid);
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(should_store == true);
|
||||
cl_assert(is_invalid == false);
|
||||
cl_assert(data == HDLC_FLAG);
|
||||
}
|
||||
|
||||
void test_hdlc__encode_decode(void) {
|
||||
const char *str = "this is a string with the special \x7e \x7d \x7e\x7d \x7d\x7e characters";
|
||||
char buffer[100];
|
||||
int write_idx = 0;
|
||||
for (int i = 0; i < strlen(str); i++) {
|
||||
char c = str[i];
|
||||
if (hdlc_encode((uint8_t *)&c)) {
|
||||
buffer[write_idx++] = HDLC_ESCAPE;
|
||||
}
|
||||
buffer[write_idx++] = c;
|
||||
}
|
||||
buffer[write_idx++] = HDLC_FLAG;
|
||||
cl_assert(write_idx == strlen(str) + 7 /* 6 special characters to escape + 1 flag at end */);
|
||||
|
||||
HdlcStreamingContext ctx;
|
||||
hdlc_streaming_decode_reset(&ctx);
|
||||
int read_idx = 0;
|
||||
int i = 0;
|
||||
while (true) {
|
||||
char c = buffer[i++];
|
||||
bool should_store, is_invalid;
|
||||
bool is_complete = hdlc_streaming_decode(&ctx, (uint8_t *)&c, &should_store, &is_invalid);
|
||||
cl_assert(is_invalid == false);
|
||||
if (should_store) {
|
||||
cl_assert(is_complete == false);
|
||||
cl_assert(c == str[read_idx++]);
|
||||
}
|
||||
if (is_complete) {
|
||||
cl_assert(should_store == false);
|
||||
cl_assert(i == write_idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cl_assert(read_idx == strlen(str));
|
||||
}
|
61
tests/fw/util/test_ihex.c
Normal file
61
tests/fw/util/test_ihex.c
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/ihex.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
|
||||
static uint8_t s_result[300];
|
||||
|
||||
|
||||
void test_ihex__initialize(void) {
|
||||
// Set the result buffer to a known value so that it can be checked
|
||||
// later to see if the code under test wrote more than it should have.
|
||||
memset(s_result, 0x20, sizeof(s_result));
|
||||
}
|
||||
|
||||
static void prv_assert_ihex(const char *expected) {
|
||||
int len = strlen(expected);
|
||||
// Cehck that bytes aren't touched past the end of the record.
|
||||
for (int i=len; i < sizeof(s_result); ++i) {
|
||||
cl_assert_equal_i(0x20, s_result[i]);
|
||||
}
|
||||
// NULL-terminate the result so that it can be compared as a string.
|
||||
s_result[len] = '\0';
|
||||
cl_assert_equal_s(expected, (char *)s_result);
|
||||
}
|
||||
|
||||
void test_ihex__eof_record(void) {
|
||||
ihex_encode(s_result, IHEX_TYPE_EOF, 0, NULL, 0);
|
||||
prv_assert_ihex(":00000001FF");
|
||||
}
|
||||
|
||||
void test_ihex__data_record(void) {
|
||||
uint8_t data[7] = { 1, 2, 3, 4, 5, 6, 7 };
|
||||
ihex_encode(s_result, IHEX_TYPE_DATA, 0xABCD, data, sizeof(data));
|
||||
prv_assert_ihex(":07ABCD000102030405060765");
|
||||
}
|
||||
|
||||
void test_ihex__empty_record_length(void) {
|
||||
cl_assert_equal_i(11, IHEX_RECORD_LENGTH(0));
|
||||
}
|
||||
|
||||
void test_ihex__record_length(void) {
|
||||
cl_assert_equal_i(15, IHEX_RECORD_LENGTH(2));
|
||||
}
|
115
tests/fw/util/test_legacy_checksum.c
Normal file
115
tests/fw/util/test_legacy_checksum.c
Normal file
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/legacy_checksum.h"
|
||||
|
||||
#include <inttypes.h>
|
||||
#include <stdio.h>
|
||||
|
||||
LegacyChecksum cksum;
|
||||
|
||||
void test_legacy_checksum__initialize(void) {
|
||||
memset(&cksum, 0xcc, sizeof cksum);
|
||||
legacy_defective_checksum_init(&cksum);
|
||||
}
|
||||
|
||||
static void update(const void * restrict data, size_t length) {
|
||||
legacy_defective_checksum_update(&cksum, data, length);
|
||||
}
|
||||
|
||||
#define assert_checksum(EXPECTED) \
|
||||
do { \
|
||||
uint32_t checksum = legacy_defective_checksum_finish(&cksum); \
|
||||
uint32_t expected = (EXPECTED); \
|
||||
if (checksum != expected) { \
|
||||
char error_msg[256]; \
|
||||
sprintf(error_msg, \
|
||||
"%#08"PRIx32" != %#08"PRIx32"\n", \
|
||||
expected, checksum); \
|
||||
clar__assert(0, __FILE__, __LINE__, \
|
||||
" expected != checksum", error_msg, 1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
|
||||
void test_legacy_checksum__no_data(void) {
|
||||
assert_checksum(0xffffffff);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__one_byte(void) {
|
||||
update("A", 1);
|
||||
assert_checksum(0xf743b0bb);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__standard(void) {
|
||||
update("123456789", 9);
|
||||
assert_checksum(0xaff19057);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__one_word(void) {
|
||||
update("1234", 4);
|
||||
assert_checksum(0xc2091428);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__repeated_byte(void) {
|
||||
update("1111", 4);
|
||||
assert_checksum(0x13cbc447);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__two_words(void) {
|
||||
update("abcd", 4);
|
||||
update("efgh", 4);
|
||||
assert_checksum(0x18c4859c);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__split_word(void) {
|
||||
update("123", 3);
|
||||
update("4", 1);
|
||||
assert_checksum(0xc2091428);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__finish_with_partial(void) {
|
||||
update("1234", 4);
|
||||
update("5", 1);
|
||||
assert_checksum(0xec5baa37);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__start_with_partial(void) {
|
||||
update("123", 3);
|
||||
update("4567", 4);
|
||||
update("8", 1);
|
||||
assert_checksum(0xfefc54f9);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__start_and_finish_with_partial(void) {
|
||||
update("12", 2);
|
||||
update("3456", 4);
|
||||
update("78", 2);
|
||||
assert_checksum(0xfefc54f9);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__long_input(void) {
|
||||
update("1234567890abcdefghijklmnopqrstuvwxyz", 36);
|
||||
assert_checksum(0x586c447d);
|
||||
}
|
||||
|
||||
void test_legacy_checksum__convenience_wrapper(void) {
|
||||
uint32_t sum = legacy_defective_checksum_memory("12345", 5);
|
||||
cl_assert_equal_i(sum, 0xec5baa37);
|
||||
}
|
125
tests/fw/util/test_lru_cache.c
Normal file
125
tests/fw/util/test_lru_cache.c
Normal file
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* 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/lru_cache.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_passert.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
const uint8_t CACHE_BUFFER_SIZE = 80;
|
||||
uint8_t s_buffer[CACHE_BUFFER_SIZE];
|
||||
LRUCache s_cache;
|
||||
|
||||
void test_lru_cache__initialize(void) {
|
||||
lru_cache_init(&s_cache, sizeof(uint32_t), s_buffer, CACHE_BUFFER_SIZE);
|
||||
}
|
||||
|
||||
void test_lru_cache__cleanup(void) {
|
||||
lru_cache_flush(&s_cache);
|
||||
}
|
||||
|
||||
void test_lru_cache__one_put(void) {
|
||||
uint32_t input = 0xdeadbeef;
|
||||
lru_cache_put(&s_cache, 1, &input);
|
||||
uint32_t *output = lru_cache_get(&s_cache, 1);
|
||||
cl_assert(output);
|
||||
cl_assert(*output == input);
|
||||
}
|
||||
|
||||
void test_lru_cache__one_put_two_get(void) {
|
||||
uint32_t input = 0xdeadbeef;
|
||||
lru_cache_put(&s_cache, 1, &input);
|
||||
|
||||
uint32_t *output;
|
||||
for (int i = 0; i < 2; i++) {
|
||||
output = lru_cache_get(&s_cache, 1);
|
||||
cl_assert(output);
|
||||
cl_assert(*output == input);
|
||||
}
|
||||
}
|
||||
|
||||
void test_lru_cache__two_puts_one_get(void) {
|
||||
uint32_t input = 0xdeadbeef;
|
||||
lru_cache_put(&s_cache, 1, &input);
|
||||
lru_cache_put(&s_cache, 1, &input);
|
||||
|
||||
uint32_t *output;
|
||||
output = lru_cache_get(&s_cache, 1);
|
||||
cl_assert(output);
|
||||
cl_assert(*output == input);
|
||||
}
|
||||
|
||||
void test_lru_cache__flush(void) {
|
||||
uint32_t input = 0xdeadbeef;
|
||||
lru_cache_put(&s_cache, 1, &input);
|
||||
lru_cache_flush(&s_cache);
|
||||
uint32_t *output = lru_cache_get(&s_cache, 1);
|
||||
cl_assert(output == NULL);
|
||||
}
|
||||
|
||||
void test_lru_cache__evict(void) {
|
||||
for (int i = 0; i <= CACHE_BUFFER_SIZE / (sizeof(CacheEntry) + sizeof(uint32_t)); ++i) {
|
||||
uint32_t input = i;
|
||||
lru_cache_put(&s_cache, i, &input);
|
||||
}
|
||||
uint32_t *output = lru_cache_get(&s_cache, 0);
|
||||
// check that the oldest entry got evicted
|
||||
cl_assert(output == NULL);
|
||||
for (int i = 1; i <= CACHE_BUFFER_SIZE / (sizeof(CacheEntry) + sizeof(uint32_t)); ++i) {
|
||||
output = lru_cache_get(&s_cache, i);
|
||||
// check that the others are still around
|
||||
cl_assert(output);
|
||||
cl_assert(*output == i);
|
||||
}
|
||||
}
|
||||
|
||||
void test_lru_cache__use_and_evict(void) {
|
||||
int i;
|
||||
for (i = 0; i < CACHE_BUFFER_SIZE / (sizeof(CacheEntry) + sizeof(uint32_t)); ++i) {
|
||||
uint32_t input = i;
|
||||
lru_cache_put(&s_cache, i, &input);
|
||||
}
|
||||
// use entry 0 to keep it around
|
||||
uint32_t *output = lru_cache_get(&s_cache, 0);
|
||||
cl_assert(output);
|
||||
cl_assert(*output == 0);
|
||||
|
||||
// add one more entry
|
||||
uint32_t input = i;
|
||||
lru_cache_put(&s_cache, i, &input);
|
||||
|
||||
// check that entry 0 is around
|
||||
output = lru_cache_get(&s_cache, 0);
|
||||
cl_assert(output);
|
||||
cl_assert(*output == 0);
|
||||
|
||||
// check that entry 1 got evicted
|
||||
output = lru_cache_get(&s_cache, 1);
|
||||
cl_assert(output == NULL);
|
||||
|
||||
// check that the others are still around
|
||||
for (int i = 2; i <= CACHE_BUFFER_SIZE / (sizeof(CacheEntry) + sizeof(uint32_t)); ++i) {
|
||||
output = lru_cache_get(&s_cache, i);
|
||||
// check that the others are still around
|
||||
cl_assert(output);
|
||||
cl_assert(*output == i);
|
||||
}
|
||||
}
|
||||
|
202
tests/fw/util/test_mbuf.c
Normal file
202
tests/fw/util/test_mbuf.c
Normal file
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/mbuf.h"
|
||||
#include "util/mbuf_iterator.h"
|
||||
|
||||
#include "stubs_logging.h"
|
||||
#include "stubs_mutex.h"
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_serial.h"
|
||||
|
||||
extern MBuf *s_free_list;
|
||||
|
||||
|
||||
// Setup
|
||||
|
||||
void test_mbuf__initialize(void) {
|
||||
}
|
||||
|
||||
void test_mbuf__cleanup(void) {
|
||||
}
|
||||
|
||||
|
||||
// Tests
|
||||
|
||||
void test_mbuf__length(void) {
|
||||
// test the mbuf_get_length()/mbuf_get_chain_length() functions
|
||||
char *data = __FILE_NAME__; // dummy data
|
||||
char data_length = sizeof(__FILE_NAME__);
|
||||
MBuf mbuf1 = MBUF_EMPTY;
|
||||
MBuf mbuf2 = MBUF_EMPTY;
|
||||
MBuf mbuf3 = MBUF_EMPTY;
|
||||
|
||||
// empty mbuf chain
|
||||
cl_assert(mbuf_get_chain_length(NULL) == 0);
|
||||
|
||||
// single empty mbuf in the chain
|
||||
mbuf1 = MBUF_EMPTY;
|
||||
cl_assert(mbuf_get_length(&mbuf1) == 0);
|
||||
cl_assert(mbuf_get_chain_length(&mbuf1) == 0);
|
||||
|
||||
// single mbuf of non-zero length
|
||||
mbuf1 = MBUF_EMPTY;
|
||||
mbuf_set_data(&mbuf1, data, data_length);
|
||||
cl_assert(mbuf_get_length(&mbuf1) == data_length);
|
||||
cl_assert(mbuf_get_chain_length(&mbuf1) == data_length);
|
||||
|
||||
// three mbufs of 0 length
|
||||
mbuf1 = MBUF_EMPTY;
|
||||
mbuf2 = MBUF_EMPTY;
|
||||
mbuf3 = MBUF_EMPTY;
|
||||
mbuf_append(&mbuf1, &mbuf2);
|
||||
mbuf_append(&mbuf1, &mbuf3);
|
||||
cl_assert(mbuf_get_length(&mbuf1) == 0);
|
||||
cl_assert(mbuf_get_chain_length(&mbuf1) == 0);
|
||||
|
||||
// three mbufs of non-zero length in a chain
|
||||
mbuf1 = MBUF_EMPTY;
|
||||
mbuf2 = MBUF_EMPTY;
|
||||
mbuf3 = MBUF_EMPTY;
|
||||
mbuf_set_data(&mbuf1, data, data_length);
|
||||
mbuf_set_data(&mbuf2, data, data_length);
|
||||
mbuf_set_data(&mbuf3, data, data_length);
|
||||
mbuf_append(&mbuf1, &mbuf2);
|
||||
mbuf_append(&mbuf1, &mbuf3);
|
||||
cl_assert(mbuf_get_length(&mbuf1) == data_length);
|
||||
cl_assert(mbuf_get_length(&mbuf2) == data_length);
|
||||
cl_assert(mbuf_get_length(&mbuf3) == data_length);
|
||||
cl_assert(mbuf_get_chain_length(&mbuf1) == (3 * data_length));
|
||||
|
||||
// three mbufs with one of zero length
|
||||
mbuf1 = MBUF_EMPTY;
|
||||
mbuf2 = MBUF_EMPTY;
|
||||
mbuf3 = MBUF_EMPTY;
|
||||
mbuf_set_data(&mbuf1, data, data_length);
|
||||
mbuf_set_data(&mbuf3, data, data_length);
|
||||
mbuf_append(&mbuf1, &mbuf2);
|
||||
mbuf_append(&mbuf1, &mbuf3);
|
||||
cl_assert(mbuf_get_length(&mbuf1) == data_length);
|
||||
cl_assert(mbuf_get_length(&mbuf2) == 0);
|
||||
cl_assert(mbuf_get_length(&mbuf3) == data_length);
|
||||
cl_assert(mbuf_get_chain_length(&mbuf1) == (2 * data_length));
|
||||
}
|
||||
|
||||
void test_mbuf__iter_empty(void) {
|
||||
// test iteratoring over empty mbuf chains
|
||||
MBuf mbuf1 = MBUF_EMPTY;
|
||||
MBuf mbuf2 = MBUF_EMPTY;
|
||||
MBufIterator iter;
|
||||
mbuf_append(&mbuf1, &mbuf2);
|
||||
mbuf_iterator_init(&iter, NULL);
|
||||
cl_assert(mbuf_iterator_is_finished(&iter));
|
||||
mbuf_iterator_init(&iter, &mbuf2);
|
||||
cl_assert(mbuf_iterator_is_finished(&iter));
|
||||
mbuf_iterator_init(&iter, &mbuf1);
|
||||
cl_assert(mbuf_iterator_is_finished(&iter));
|
||||
uint8_t data;
|
||||
cl_assert(!mbuf_iterator_read_byte(&iter, &data));
|
||||
cl_assert(!mbuf_iterator_get_current_mbuf(&iter));
|
||||
}
|
||||
|
||||
void test_mbuf__iter_modify(void) {
|
||||
// modify (read and then write) the data in an mbuf chain using an mbuf iterator
|
||||
// test reading from an mbuf chain via an mbuf iterator
|
||||
uint8_t data1[] = {10, 11, 12};
|
||||
uint8_t data3[] = {13, 14, 15};
|
||||
MBufIterator write_iter, read_iter;
|
||||
MBuf mbuf1 = MBUF_EMPTY;
|
||||
MBuf mbuf2 = MBUF_EMPTY;
|
||||
MBuf mbuf3 = MBUF_EMPTY;
|
||||
mbuf_set_data(&mbuf1, data1, 3);
|
||||
mbuf_set_data(&mbuf3, data3, 3);
|
||||
mbuf_append(&mbuf1, &mbuf2);
|
||||
mbuf_append(&mbuf1, &mbuf3);
|
||||
mbuf_iterator_init(&write_iter, &mbuf1);
|
||||
mbuf_iterator_init(&read_iter, &mbuf1);
|
||||
for (int i = 0; i < 6; i++) {
|
||||
cl_assert(!mbuf_iterator_is_finished(&write_iter));
|
||||
cl_assert(!mbuf_iterator_is_finished(&read_iter));
|
||||
// check we're on the exected mbuf
|
||||
if (i < 3) {
|
||||
cl_assert(mbuf_iterator_get_current_mbuf(&write_iter) == &mbuf1);
|
||||
cl_assert(mbuf_iterator_get_current_mbuf(&read_iter) == &mbuf1);
|
||||
} else {
|
||||
cl_assert(mbuf_iterator_get_current_mbuf(&write_iter) == &mbuf3);
|
||||
cl_assert(mbuf_iterator_get_current_mbuf(&read_iter) == &mbuf3);
|
||||
}
|
||||
uint8_t data_byte = 0;
|
||||
bool have_byte = mbuf_iterator_read_byte(&read_iter, &data_byte);
|
||||
cl_assert(have_byte);
|
||||
// check that the data is what we expect
|
||||
cl_assert(data_byte == (i + 10));
|
||||
// modify the data by increasing the value by 10
|
||||
cl_assert(mbuf_iterator_write_byte(&write_iter, data_byte + 10));
|
||||
}
|
||||
cl_assert(mbuf_iterator_is_finished(&write_iter));
|
||||
cl_assert(mbuf_iterator_is_finished(&read_iter));
|
||||
// verify the final value of the data
|
||||
for (int i = 0; i < 6; i++) {
|
||||
uint8_t *data;
|
||||
int index;
|
||||
if (i < 3) {
|
||||
data = data1;
|
||||
index = i;
|
||||
} else {
|
||||
data = data3;
|
||||
index = i - 3;
|
||||
}
|
||||
cl_assert(data[index] == (i + 20));
|
||||
}
|
||||
}
|
||||
|
||||
static int prv_get_free_list_length(void) {
|
||||
int len = 0;
|
||||
for (MBuf *m = s_free_list; m; m = mbuf_get_next(m)) {
|
||||
len++;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
void test_mbuf__mbuf_pool(void) {
|
||||
// get an MBuf and the pool should still be empty
|
||||
MBuf *mbuf1 = mbuf_get(NULL, 0, MBufPoolUnitTest);
|
||||
cl_assert(prv_get_free_list_length() == 0);
|
||||
|
||||
// free the mbuf and the pool should now contain it
|
||||
mbuf_free(mbuf1);
|
||||
cl_assert(prv_get_free_list_length() == 1);
|
||||
cl_assert(s_free_list == mbuf1);
|
||||
|
||||
// get another mbuf and expect that it's the same one and the pool is empty
|
||||
MBuf *mbuf2 = mbuf_get(NULL, 0, MBufPoolUnitTest);
|
||||
cl_assert(mbuf2 == mbuf1);
|
||||
cl_assert(prv_get_free_list_length() == 0);
|
||||
|
||||
// get another mbuf and expect that it's not the same as the previous one
|
||||
MBuf *mbuf3 = mbuf_get(NULL, 0, MBufPoolUnitTest);
|
||||
cl_assert(mbuf3 != mbuf2);
|
||||
cl_assert(prv_get_free_list_length() == 0);
|
||||
|
||||
// free both of the mbufs (one at a time)
|
||||
mbuf_free(mbuf2);
|
||||
cl_assert(prv_get_free_list_length() == 1);
|
||||
mbuf_free(mbuf3);
|
||||
cl_assert(prv_get_free_list_length() == 2);
|
||||
}
|
89
tests/fw/util/test_mktime.c
Normal file
89
tests/fw/util/test_mktime.c
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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 <math.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <clar.h>
|
||||
|
||||
// Tests
|
||||
///////////////////////////////////////////////////////////
|
||||
void test_mktime__bithdays(void) {
|
||||
struct tm francois_birthday = {
|
||||
.tm_sec = 0,
|
||||
.tm_min = 44,
|
||||
.tm_hour = 10,
|
||||
.tm_mday = 30,
|
||||
.tm_mon = 4,
|
||||
.tm_year = 89,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&francois_birthday), 612528240);
|
||||
|
||||
struct tm rons_birthday = {
|
||||
.tm_sec = 17,
|
||||
.tm_min = 1,
|
||||
.tm_hour = 9,
|
||||
.tm_mday = 10,
|
||||
.tm_mon = 4,
|
||||
.tm_year = 63,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&rons_birthday), -1);
|
||||
|
||||
struct tm alex_marianetti_birthday = {
|
||||
.tm_sec = 29,
|
||||
.tm_min = 4,
|
||||
.tm_hour = 17,
|
||||
.tm_mday = 2,
|
||||
.tm_mon = 9,
|
||||
.tm_year = 107,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&alex_marianetti_birthday), 1191344669);
|
||||
|
||||
struct tm chris_birthday = {
|
||||
.tm_sec = 59,
|
||||
.tm_min = 3,
|
||||
.tm_hour = 10,
|
||||
.tm_mday = 15,
|
||||
.tm_mon = 5,
|
||||
.tm_year = 89,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&chris_birthday), 613908239);
|
||||
}
|
||||
|
||||
void test_mktime__epoch(void) {
|
||||
struct tm epoch = {
|
||||
.tm_sec = 0,
|
||||
.tm_min = 0,
|
||||
.tm_hour = 0,
|
||||
.tm_mday = 1,
|
||||
.tm_mon = 0,
|
||||
.tm_year = 70,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&epoch), 0);
|
||||
}
|
||||
|
||||
void test_mktime__leap(void) {
|
||||
struct tm real_leap = {
|
||||
.tm_sec = 0,
|
||||
.tm_min = 0,
|
||||
.tm_hour = 10,
|
||||
.tm_mday = 29,
|
||||
.tm_mon = 1,
|
||||
.tm_year = 112,
|
||||
};
|
||||
cl_assert_equal_i(mktime(&real_leap), 1330509600);
|
||||
}
|
||||
|
81
tests/fw/util/test_pstring.c
Normal file
81
tests/fw/util/test_pstring.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/pstring.h"
|
||||
|
||||
|
||||
#include "stubs_pbl_malloc.h"
|
||||
#include "stubs_logging.h"
|
||||
|
||||
|
||||
void test_pstring__initialize(void) {
|
||||
}
|
||||
|
||||
void test_pstring__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_pstring__equal(void) {
|
||||
const char *ps1_str = "Phil";
|
||||
uint8_t ps1_buf[128];
|
||||
PascalString16 *ps1 = (PascalString16 *)&ps1_buf;
|
||||
ps1->str_length = strlen(ps1_str);
|
||||
memcpy(ps1->str_value, ps1_str, strlen(ps1_str));
|
||||
|
||||
const char *ps2_str = "Four";
|
||||
uint8_t ps2_buf[128];
|
||||
PascalString16 *ps2 = (PascalString16 *)&ps2_buf;
|
||||
ps2->str_length = strlen(ps2_str);
|
||||
memcpy(ps2->str_value, ps2_str, strlen(ps2_str));
|
||||
|
||||
const char *ps3_str = "PhilG";
|
||||
uint8_t ps3_buf[128];
|
||||
PascalString16 *ps3 = (PascalString16 *)&ps3_buf;
|
||||
ps3->str_length = strlen(ps3_str);
|
||||
memcpy(ps3->str_value, ps3_str, strlen(ps3_str));
|
||||
|
||||
const char *ps4_str = "Phil";
|
||||
uint8_t ps4_buf[128];
|
||||
PascalString16 *ps4 = (PascalString16 *)&ps4_buf;
|
||||
ps4->str_length = strlen(ps4_str);
|
||||
memcpy(ps4->str_value, ps4_str, strlen(ps4_str));
|
||||
|
||||
|
||||
cl_assert(pstring_equal(ps1, ps4));
|
||||
cl_assert(!pstring_equal(ps1, ps2));
|
||||
cl_assert(!pstring_equal(ps1, ps3));
|
||||
cl_assert(!pstring_equal(ps2, ps3));
|
||||
cl_assert(!pstring_equal(ps1, NULL));
|
||||
cl_assert(!pstring_equal(NULL, NULL));
|
||||
}
|
||||
|
||||
void test_pstring__equal_cstring(void) {
|
||||
const char *str1 = "Phil";
|
||||
uint8_t ps1_buf[128];
|
||||
PascalString16 *ps1 = (PascalString16 *)&ps1_buf;
|
||||
ps1->str_length = strlen(str1);
|
||||
memcpy(ps1->str_value, str1, strlen(str1));
|
||||
|
||||
|
||||
const char *str2 = "PhilG";
|
||||
|
||||
|
||||
cl_assert(pstring_equal_cstring(ps1, str1));
|
||||
cl_assert(!pstring_equal_cstring(ps1, str2));
|
||||
cl_assert(!pstring_equal_cstring(ps1, NULL));
|
||||
cl_assert(!pstring_equal_cstring(NULL, NULL));
|
||||
}
|
49
tests/fw/util/test_rand.c
Normal file
49
tests/fw/util/test_rand.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <clar.h>
|
||||
|
||||
#include "kernel/pebble_tasks.h"
|
||||
#include "util/rand.h"
|
||||
|
||||
// Stubs
|
||||
///////////////////////////////////////////////////////////
|
||||
#include "stubs_passert.h"
|
||||
#include "stubs_rand_ptr.h"
|
||||
|
||||
PebbleTask pebble_task_get_current(void) {
|
||||
return PebbleTask_KernelMain; // System seed
|
||||
}
|
||||
|
||||
// Tests
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
void test_rand__smoke_test(void) {
|
||||
#define RANDOM_CHECK_LENGTH 512
|
||||
|
||||
uint32_t values[RANDOM_CHECK_LENGTH];
|
||||
for(size_t i = 0; i < RANDOM_CHECK_LENGTH; i++) {
|
||||
values[i] = rand32();
|
||||
for(size_t l = 0; l < i; l++) {
|
||||
printf("i,l: %zu,%zu\n", i,l);
|
||||
cl_assert(values[i] != values[l]);
|
||||
}
|
||||
}
|
||||
}
|
373
tests/fw/util/test_shared_circular_buffer.c
Normal file
373
tests/fw/util/test_shared_circular_buffer.c
Normal file
|
@ -0,0 +1,373 @@
|
|||
/*
|
||||
* 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/shared_circular_buffer.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "stubs_passert.h"
|
||||
|
||||
|
||||
// Stubs
|
||||
///////////////////////////////////////////////////////////
|
||||
int g_pbl_log_level = 0;
|
||||
void pbl_log(int level, const char* src_filename, int src_line_number, const char* fmt, ...) { }
|
||||
|
||||
|
||||
void test_shared_circular_buffer__initialize(void) {
|
||||
}
|
||||
|
||||
void test_shared_circular_buffer__cleanup(void) {
|
||||
}
|
||||
|
||||
static void prv_read_and_consume(SharedCircularBuffer *buffer, SharedCircularBufferClient *client,
|
||||
uint8_t *data, uint32_t num_bytes) {
|
||||
while (num_bytes) {
|
||||
uint16_t chunk;
|
||||
const uint8_t *read_ptr;
|
||||
|
||||
cl_assert(shared_circular_buffer_read(buffer, client, num_bytes, &read_ptr, &chunk));
|
||||
memcpy(data, read_ptr, chunk);
|
||||
cl_assert(shared_circular_buffer_consume(buffer, client, chunk));
|
||||
|
||||
buffer += chunk;
|
||||
num_bytes -= chunk;
|
||||
}
|
||||
}
|
||||
|
||||
void test_shared_circular_buffer__one_client(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint8_t storage[9];
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
|
||||
const uint8_t* out_buffer;
|
||||
uint16_t out_length;
|
||||
|
||||
// Add a client
|
||||
SharedCircularBufferClient client = (SharedCircularBufferClient) {};
|
||||
shared_circular_buffer_add_client(&buffer, &client);
|
||||
|
||||
// We should start out empty
|
||||
cl_assert(!shared_circular_buffer_read(&buffer, &client, 1, &out_buffer, &out_length));
|
||||
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "123", 3, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 5);
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "456", 3, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 2);
|
||||
cl_assert(!shared_circular_buffer_write(&buffer, (uint8_t*) "789", 3, false)); // too big
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 2);
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client, 4, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 4);
|
||||
cl_assert(memcmp(out_buffer, "1234", 4) == 0);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 2);
|
||||
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client, 4));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 6);
|
||||
|
||||
// Now there's just 56 in the buffer. Fill it to the brim
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "789", 3, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 3);
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "abc", 3, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 0);
|
||||
cl_assert(!shared_circular_buffer_write(&buffer, (uint8_t*) "d", 1, false)); // too full
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 0);
|
||||
|
||||
// Try a wrapped read
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client, 6, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 5);
|
||||
cl_assert(memcmp(out_buffer, (uint8_t*) "56789", 5) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client, 5));
|
||||
|
||||
// Get the rest of the wrapped read
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client, 1, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 1);
|
||||
cl_assert(memcmp(out_buffer, (uint8_t*) "a", 1) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client, 1));
|
||||
|
||||
// Consume one without reading it
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client, 1));
|
||||
|
||||
// Read the last little bit
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client, 1, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 1);
|
||||
cl_assert(memcmp(out_buffer, (uint8_t*) "c", 1) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client, 1));
|
||||
|
||||
// And we should be empty
|
||||
cl_assert(!shared_circular_buffer_read(&buffer, &client, 1, &out_buffer, &out_length));
|
||||
cl_assert(!shared_circular_buffer_consume(&buffer, &client, 1));
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__two_clients(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint8_t storage[9];
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
|
||||
const uint8_t* out_buffer;
|
||||
uint16_t out_length;
|
||||
|
||||
// Add clients
|
||||
SharedCircularBufferClient client1 = (SharedCircularBufferClient) {};
|
||||
shared_circular_buffer_add_client(&buffer, &client1);
|
||||
SharedCircularBufferClient client2 = (SharedCircularBufferClient) {};
|
||||
shared_circular_buffer_add_client(&buffer, &client2);
|
||||
|
||||
// We should start out empty
|
||||
cl_assert(!shared_circular_buffer_read(&buffer, &client1, 1, &out_buffer, &out_length));
|
||||
cl_assert(!shared_circular_buffer_read(&buffer, &client2, 1, &out_buffer, &out_length));
|
||||
|
||||
// Fill with data
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "123456", 6, false));
|
||||
|
||||
// Read different amounts from each client
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client1, 4, &out_buffer, &out_length));
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client1, 4));
|
||||
cl_assert(memcmp(out_buffer, "1234", 4) == 0);
|
||||
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 2);
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client2, 4, &out_buffer, &out_length));
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client2, 4));
|
||||
cl_assert(memcmp(out_buffer, "1234", 4) == 0);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 6);
|
||||
|
||||
|
||||
// Make client2 fall behind
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "abcdef", 6, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 0);
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client1, 3, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 3);
|
||||
cl_assert(memcmp(out_buffer, "56a", 3) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client1, 3));
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client1, 2, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 2);
|
||||
cl_assert(memcmp(out_buffer, "bc", 2) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client1, 2));
|
||||
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 0);
|
||||
|
||||
|
||||
// Should fail, not enough room because client 2 is full
|
||||
cl_assert(!shared_circular_buffer_write(&buffer, (uint8_t*) "gh", 2, false));
|
||||
|
||||
// This should pass and reset client 2's read index
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "gh", 2, true));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 3);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client1), 5);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client2), 2);
|
||||
|
||||
|
||||
// Make client2 fall behind again
|
||||
cl_assert(shared_circular_buffer_write(&buffer, (uint8_t*) "abc", 3, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 0);
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client1, 3, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 3);
|
||||
cl_assert(memcmp(out_buffer, "def", 3) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client1, 3));
|
||||
|
||||
cl_assert(shared_circular_buffer_read(&buffer, &client1, 2, &out_buffer, &out_length));
|
||||
cl_assert_equal_i(out_length, 2);
|
||||
cl_assert(memcmp(out_buffer, "gh", 2) == 0);
|
||||
cl_assert(shared_circular_buffer_consume(&buffer, &client1, 2));
|
||||
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client1), 3);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client2), 5);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 3);
|
||||
|
||||
// If we remove client2, it should create more space
|
||||
shared_circular_buffer_remove_client(&buffer, &client2);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_write_space_remaining(&buffer), 5);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__corner_case(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint8_t storage[4];
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
|
||||
// Add a client
|
||||
SharedCircularBufferClient client = (SharedCircularBufferClient) {};
|
||||
shared_circular_buffer_add_client(&buffer, &client);
|
||||
|
||||
// We should start out empty
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client), 0);
|
||||
|
||||
// Write 2
|
||||
cl_assert(shared_circular_buffer_write(&buffer, storage, 2, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client), 2);
|
||||
|
||||
// Consume it
|
||||
prv_read_and_consume(&buffer, &client, storage, 2);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client), 0);
|
||||
|
||||
// Write 2 more
|
||||
cl_assert(shared_circular_buffer_write(&buffer, storage, 2, false));
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client), 2);
|
||||
|
||||
// Consume it
|
||||
prv_read_and_consume(&buffer, &client, storage, 2);
|
||||
cl_assert_equal_i(shared_circular_buffer_get_read_space_remaining(&buffer, &client), 0);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__subsampling_2of5(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint16_t item_size = 2;
|
||||
uint8_t storage[12*item_size];
|
||||
uint8_t out_buffer[12*item_size];
|
||||
uint16_t items_read;
|
||||
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
SubsampledSharedCircularBufferClient client = {};
|
||||
shared_circular_buffer_add_subsampled_client(&buffer, &client, 2, 5);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0a1b2c3d4e5f6g7h8i", 9*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 100);
|
||||
cl_assert_equal_i(items_read, 4);
|
||||
cl_assert_equal_m(out_buffer, "0a3d5f8i", 8);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"9j0k1m2n3o4p5q", 7*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 2);
|
||||
cl_assert_equal_i(items_read, 2);
|
||||
cl_assert_equal_m(out_buffer, "0k3o", 4);
|
||||
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 2);
|
||||
cl_assert_equal_i(items_read, 1);
|
||||
cl_assert_equal_m(out_buffer, "5q", 2);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__subsampling_1of3(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint16_t item_size = 2;
|
||||
uint8_t storage[12*item_size];
|
||||
uint8_t out_buffer[12*item_size];
|
||||
uint16_t items_read;
|
||||
|
||||
// Init
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
SubsampledSharedCircularBufferClient client = {};
|
||||
shared_circular_buffer_add_subsampled_client(&buffer, &client, 1, 3);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0a1b2c3d4e5f6g7h8i9j", 10*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 100);
|
||||
cl_assert_equal_i(items_read, 4);
|
||||
cl_assert_equal_m(out_buffer, "0a3d6g9j", 8);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0k1m2n", 3*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 100);
|
||||
cl_assert_equal_i(items_read, 1);
|
||||
cl_assert_equal_m(out_buffer, "2n", 2);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__subsampling_1of1(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint16_t item_size = 2;
|
||||
uint8_t storage[12*item_size];
|
||||
uint8_t out_buffer[12*item_size];
|
||||
uint16_t items_read;
|
||||
|
||||
// Init
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
SubsampledSharedCircularBufferClient client = {};
|
||||
shared_circular_buffer_add_subsampled_client(&buffer, &client, 3, 3);
|
||||
|
||||
// No subsampling
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0a1b2c3d4e5f6g7h8i9j", 10*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 9);
|
||||
cl_assert_equal_i(items_read, 9);
|
||||
cl_assert_equal_m(out_buffer, "0a1b2c3d4e5f6g7h8i", 18);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0k1m", 2*item_size, false));
|
||||
items_read = shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 100);
|
||||
cl_assert_equal_i(items_read, 3);
|
||||
cl_assert_equal_m(out_buffer, "9j0k1m", 6);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__subsampling_variable_ratio(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint16_t item_size = 2;
|
||||
uint8_t storage[12*item_size];
|
||||
uint8_t out_buffer[12*item_size];
|
||||
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
SubsampledSharedCircularBufferClient client = {};
|
||||
shared_circular_buffer_add_subsampled_client(&buffer, &client, 1, 2);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0a1b2c3d4e5f6g7h8i9j", 10*item_size, false));
|
||||
// Consume "0a1b2c3d4e"
|
||||
cl_assert_equal_i(shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 3), 3);
|
||||
cl_assert_equal_m(out_buffer, "0a2c4e", 6);
|
||||
|
||||
subsampled_shared_circular_buffer_client_set_ratio(&client, 2, 3);
|
||||
// Consume "5f6g7h8i"
|
||||
cl_assert_equal_i(shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 3), 3);
|
||||
// Normally the next read would skip 5f, but changing the ratio resets the
|
||||
// subsampling state and the first sample after resetting the state is never
|
||||
// skipped.
|
||||
cl_assert_equal_m(out_buffer, "5f7h8i", 6);
|
||||
}
|
||||
|
||||
|
||||
void test_shared_circular_buffer__subsampling_set_ratio_is_idempotent(void) {
|
||||
SharedCircularBuffer buffer;
|
||||
uint16_t item_size = 2;
|
||||
uint8_t storage[12*item_size];
|
||||
uint8_t out_buffer[12*item_size];
|
||||
|
||||
shared_circular_buffer_init(&buffer, storage, sizeof(storage));
|
||||
SubsampledSharedCircularBufferClient client = {};
|
||||
shared_circular_buffer_add_subsampled_client(&buffer, &client, 1, 2);
|
||||
|
||||
cl_assert(shared_circular_buffer_write(
|
||||
&buffer, (uint8_t*)"0a1b2c3d4e5f6g7h8i9j", 10*item_size, false));
|
||||
// Consume "0a1b2c3d4e"
|
||||
cl_assert_equal_i(shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 3), 3);
|
||||
cl_assert_equal_m(out_buffer, "0a2c4e", 6);
|
||||
|
||||
// This should be a no-op. the "5f" sample should still be skipped on the next
|
||||
// read.
|
||||
subsampled_shared_circular_buffer_client_set_ratio(&client, 1, 2);
|
||||
cl_assert_equal_i(shared_circular_buffer_read_subsampled(
|
||||
&buffer, &client, item_size, out_buffer, 1), 1);
|
||||
cl_assert_equal_m(out_buffer, "6g", 2);
|
||||
}
|
95
tests/fw/util/test_sle.c
Normal file
95
tests/fw/util/test_sle.c
Normal file
|
@ -0,0 +1,95 @@
|
|||
/*
|
||||
* 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 "clar.h"
|
||||
|
||||
#include "util/sle.h"
|
||||
|
||||
#include "stubs/stubs_passert.h"
|
||||
|
||||
void test_sle__simple(void) {
|
||||
SLEDecodeContext ctx;
|
||||
uint8_t buf[] = {
|
||||
0xfd, // escape code
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
||||
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0xfd, 0x00 // end
|
||||
};
|
||||
sle_decode_init(&ctx, buf);
|
||||
|
||||
uint8_t byte;
|
||||
uint8_t expect = 0x00;
|
||||
uint32_t count = 0;
|
||||
while (sle_decode(&ctx, &byte)) {
|
||||
cl_assert_equal_i(byte, expect++);
|
||||
++count;
|
||||
}
|
||||
cl_assert_equal_i(count, 16);
|
||||
}
|
||||
|
||||
void test_sle__short_zeros(void) {
|
||||
SLEDecodeContext ctx;
|
||||
uint8_t buf[] = {
|
||||
0xfd, // escape code
|
||||
0xfd, 0x5, // 5 zeroes
|
||||
0xfd, 0x00 // end
|
||||
};
|
||||
sle_decode_init(&ctx, buf);
|
||||
|
||||
uint8_t byte;
|
||||
uint32_t count = 0;
|
||||
while (sle_decode(&ctx, &byte)) {
|
||||
cl_assert_equal_i(byte, 0x0);
|
||||
++count;
|
||||
}
|
||||
cl_assert_equal_i(count, 5);
|
||||
}
|
||||
|
||||
void test_sle__long_zeros(void) {
|
||||
SLEDecodeContext ctx;
|
||||
uint8_t buf[] = {
|
||||
0xfd, // escape code
|
||||
0xfd, 0xff, 0xaa, // 32810 zeroes
|
||||
0xfd, 0x00 // end
|
||||
};
|
||||
sle_decode_init(&ctx, buf);
|
||||
|
||||
uint8_t byte;
|
||||
uint32_t count = 0;
|
||||
while (sle_decode(&ctx, &byte)) {
|
||||
cl_assert_equal_i(byte, 0x0);
|
||||
++count;
|
||||
}
|
||||
cl_assert_equal_i(count, 32810);
|
||||
}
|
||||
|
||||
void test_sle__escape_byte(void) {
|
||||
SLEDecodeContext ctx;
|
||||
uint8_t buf[] = {
|
||||
0xfd, // escape code
|
||||
0xfd, 0x01, // literal escape byte
|
||||
0xfd, 0x00 // end
|
||||
};
|
||||
sle_decode_init(&ctx, buf);
|
||||
|
||||
uint8_t byte;
|
||||
uint32_t count = 0;
|
||||
while (sle_decode(&ctx, &byte)) {
|
||||
cl_assert_equal_i(byte, 0xfd);
|
||||
++count;
|
||||
}
|
||||
cl_assert_equal_i(count, 1);
|
||||
}
|
358
tests/fw/util/test_stats.c
Normal file
358
tests/fw/util/test_stats.c
Normal file
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* 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/size.h"
|
||||
#include "util/stats.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "stubs_pbl_malloc.h"
|
||||
|
||||
void test_stats__initialize(void) {
|
||||
}
|
||||
|
||||
void test_stats__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_stats__min(void) {
|
||||
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Min;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 6);
|
||||
}
|
||||
|
||||
void test_stats__max(void) {
|
||||
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Max;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 80);
|
||||
}
|
||||
|
||||
void test_stats__avg(void) {
|
||||
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Average;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 40);
|
||||
}
|
||||
|
||||
void test_stats__sum(void) {
|
||||
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Sum;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 362);
|
||||
}
|
||||
|
||||
static void *s_context = NULL;
|
||||
|
||||
static bool prv_filter(int index, int32_t value, void *context) {
|
||||
cl_assert_equal_p(context, &s_context);
|
||||
return (value > 0);
|
||||
}
|
||||
|
||||
void test_stats__filtered_count(void) {
|
||||
const int32_t data[] = { 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Count;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
|
||||
cl_assert_equal_i(result, 14);
|
||||
}
|
||||
|
||||
void test_stats__filtered_consecutive(void) {
|
||||
const int32_t data[] = { 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Consecutive;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
|
||||
cl_assert_equal_i(result, 5);
|
||||
}
|
||||
|
||||
void test_stats__filtered_consecutive_first(void) {
|
||||
const int32_t data[] = { 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_ConsecutiveFirst;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result);
|
||||
cl_assert_equal_i(result, 3);
|
||||
}
|
||||
|
||||
void test_stats__median(void) {
|
||||
const int32_t data[] = { 10, 40, 6, 32, 73, 80, 34, 25, 62 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op = StatsBasicOp_Median;
|
||||
int32_t result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 34);
|
||||
}
|
||||
|
||||
void test_stats__all_basic_ops(void) {
|
||||
const int32_t data[] = { 10, 0, 40, 6, 0, -5, 0, 32, 73, 0, 80, 34, 25, 62, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op =
|
||||
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
|
||||
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
|
||||
StatsBasicOp_Median);
|
||||
struct {
|
||||
int32_t sum;
|
||||
int32_t avg;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t count;
|
||||
int32_t max_streak;
|
||||
int32_t first_streak;
|
||||
int32_t median;
|
||||
} result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
|
||||
cl_assert_equal_i(result.sum, 357);
|
||||
cl_assert_equal_i(result.avg, 23);
|
||||
cl_assert_equal_i(result.min, -5);
|
||||
cl_assert_equal_i(result.max, 80);
|
||||
cl_assert_equal_i(result.count, num_data);
|
||||
cl_assert_equal_i(result.max_streak, num_data);
|
||||
cl_assert_equal_i(result.first_streak, num_data);
|
||||
cl_assert_equal_i(result.median, 10);
|
||||
}
|
||||
|
||||
void test_stats__all_basic_ops_filtered(void) {
|
||||
const int32_t data[] = { 10, 0, 40, 6, 0, 0, 0, 32, 73, 0, 80, 34, 25, 62, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op =
|
||||
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
|
||||
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
|
||||
StatsBasicOp_Median);
|
||||
struct {
|
||||
int32_t sum;
|
||||
int32_t avg;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t count;
|
||||
int32_t max_streak;
|
||||
int32_t first_streak;
|
||||
int32_t median;
|
||||
} result;
|
||||
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result.sum);
|
||||
cl_assert_equal_i(result.sum, 362);
|
||||
cl_assert_equal_i(result.avg, 40);
|
||||
cl_assert_equal_i(result.min, 6);
|
||||
cl_assert_equal_i(result.max, 80);
|
||||
cl_assert_equal_i(result.count, 9);
|
||||
cl_assert_equal_i(result.max_streak, 4);
|
||||
cl_assert_equal_i(result.first_streak, 1);
|
||||
cl_assert_equal_i(result.median, 34);
|
||||
}
|
||||
|
||||
void test_stats__all_basic_ops_filtered_out(void) {
|
||||
const int32_t data[] = { 0, 0, 0, 0, 0 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op =
|
||||
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
|
||||
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
|
||||
StatsBasicOp_Median);
|
||||
struct {
|
||||
int32_t sum;
|
||||
int32_t avg;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t count;
|
||||
int32_t max_streak;
|
||||
int32_t first_streak;
|
||||
int32_t median;
|
||||
} result;
|
||||
stats_calculate_basic(op, data, num_data, prv_filter, &s_context, &result.sum);
|
||||
cl_assert_equal_i(result.sum, 0);
|
||||
cl_assert_equal_i(result.avg, 0);
|
||||
cl_assert_equal_i(result.min, INT32_MAX);
|
||||
cl_assert_equal_i(result.max, INT32_MIN);
|
||||
cl_assert_equal_i(result.count, 0);
|
||||
cl_assert_equal_i(result.max_streak, 0);
|
||||
cl_assert_equal_i(result.first_streak, 0);
|
||||
cl_assert_equal_i(result.median, 0);
|
||||
}
|
||||
|
||||
void test_stats__all_basic_one_value(void) {
|
||||
const int32_t data[] = { 42 };
|
||||
const size_t num_data = ARRAY_LENGTH(data);
|
||||
const StatsBasicOp op =
|
||||
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
|
||||
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
|
||||
StatsBasicOp_Median);
|
||||
struct {
|
||||
int32_t sum;
|
||||
int32_t avg;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t count;
|
||||
int32_t max_streak;
|
||||
int32_t first_streak;
|
||||
int32_t median;
|
||||
} result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
|
||||
cl_assert_equal_i(result.sum, 42);
|
||||
cl_assert_equal_i(result.avg, 42);
|
||||
cl_assert_equal_i(result.min, 42);
|
||||
cl_assert_equal_i(result.max, 42);
|
||||
cl_assert_equal_i(result.count, 1);
|
||||
cl_assert_equal_i(result.max_streak, 1);
|
||||
cl_assert_equal_i(result.first_streak, 1);
|
||||
cl_assert_equal_i(result.median, 42);
|
||||
}
|
||||
|
||||
void test_stats__all_basic_no_values(void) {
|
||||
const int32_t data[] = {};
|
||||
const size_t num_data = 0;
|
||||
const StatsBasicOp op =
|
||||
(StatsBasicOp_Sum | StatsBasicOp_Average | StatsBasicOp_Min | StatsBasicOp_Max |
|
||||
StatsBasicOp_Count | StatsBasicOp_Consecutive | StatsBasicOp_ConsecutiveFirst |
|
||||
StatsBasicOp_Median);
|
||||
struct {
|
||||
int32_t sum;
|
||||
int32_t avg;
|
||||
int32_t min;
|
||||
int32_t max;
|
||||
int32_t count;
|
||||
int32_t max_streak;
|
||||
int32_t first_streak;
|
||||
int32_t median;
|
||||
} result;
|
||||
stats_calculate_basic(op, data, num_data, NULL, NULL, &result.sum);
|
||||
cl_assert_equal_i(result.sum, 0);
|
||||
cl_assert_equal_i(result.avg, 0);
|
||||
cl_assert_equal_i(result.min, INT32_MAX);
|
||||
cl_assert_equal_i(result.max, INT32_MIN);
|
||||
cl_assert_equal_i(result.count, 0);
|
||||
cl_assert_equal_i(result.max_streak, 0);
|
||||
cl_assert_equal_i(result.first_streak, 0);
|
||||
cl_assert_equal_i(result.median, 0);
|
||||
}
|
||||
|
||||
void test_stats__null_data(void) {
|
||||
const StatsBasicOp op = StatsBasicOp_Average;
|
||||
int32_t result = 0x73110;
|
||||
stats_calculate_basic(op, NULL, 0, NULL, NULL, &result);
|
||||
cl_assert_equal_i(result, 0x73110);
|
||||
}
|
||||
|
||||
typedef struct WeightedValue {
|
||||
int32_t value;
|
||||
int32_t weight_x100;
|
||||
} WeightedValue;
|
||||
|
||||
void test_stats__weighted_median(void) {
|
||||
//! Taken from https://en.wikipedia.org/wiki/Weighted_median
|
||||
struct {
|
||||
int32_t values[10];
|
||||
int32_t weights[10];
|
||||
int32_t num_values;
|
||||
int32_t answer;
|
||||
} test_cases[] = {
|
||||
{
|
||||
// Simple test case
|
||||
.values = {1, 3, 1},
|
||||
.weights = {2, 4, 1},
|
||||
.num_values = 3,
|
||||
.answer = 3,
|
||||
},
|
||||
{
|
||||
// Hit exactly S/2 when iterating. Take the mean of [1,2] and [3,4] -> 2
|
||||
.values = {1, 3, 1},
|
||||
.weights = {2, 4, 2},
|
||||
.num_values = 3,
|
||||
.answer = 2,
|
||||
},
|
||||
{
|
||||
// Would hit exactly S/2 when iterating if we only did integer division. Added a check to
|
||||
// prevent this.
|
||||
.values = {1, 3, 1},
|
||||
.weights = {2, 4, 3},
|
||||
.num_values = 3,
|
||||
.answer = 1,
|
||||
},
|
||||
{
|
||||
// Simple test case
|
||||
.values = {1, 100},
|
||||
.weights = {2, 1},
|
||||
.num_values = 2,
|
||||
.answer = 1,
|
||||
},
|
||||
{
|
||||
// Simple test case
|
||||
.values = {100, 1},
|
||||
.weights = {1, 2},
|
||||
.num_values = 2,
|
||||
.answer = 1,
|
||||
},
|
||||
{
|
||||
// Simple test case
|
||||
.values = {100, 1},
|
||||
.weights = {2, 1},
|
||||
.num_values = 2,
|
||||
.answer = 100,
|
||||
},
|
||||
{
|
||||
// Simple test case
|
||||
.values = {20, 3, 6},
|
||||
.weights = {1, 50, 50},
|
||||
.num_values = 3,
|
||||
.answer = 6,
|
||||
},
|
||||
{
|
||||
// Test if all weights are zero, zero should be returned
|
||||
.values = {20, 3, 6},
|
||||
.weights = {0, 0, 0},
|
||||
.num_values = 3,
|
||||
.answer = 0,
|
||||
},
|
||||
{
|
||||
// Simple test case
|
||||
.values = {10, 35, 5, 10, 15, 5, 20},
|
||||
.weights = {20, 70, 10, 20, 30, 10, 40},
|
||||
.num_values = 7,
|
||||
.answer = 20,
|
||||
},
|
||||
{
|
||||
// Only one value, return that value
|
||||
.values = {1},
|
||||
.weights = {100},
|
||||
.num_values = 1,
|
||||
.answer = 1,
|
||||
},
|
||||
{
|
||||
// Two values, equal weight. Return the lower of the two
|
||||
.values = {1, 2},
|
||||
.weights = {1, 1},
|
||||
.num_values = 2,
|
||||
.answer = 1,
|
||||
},
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < ARRAY_LENGTH(test_cases); i++) {
|
||||
int32_t w_median = stats_calculate_weighted_median(test_cases[i].values,
|
||||
test_cases[i].weights,
|
||||
test_cases[i].num_values);
|
||||
printf("W_Median test case: %d\n", (int)i);
|
||||
cl_assert_equal_i(test_cases[i].answer, w_median);
|
||||
}
|
||||
}
|
144
tests/fw/util/test_stringlist.c
Normal file
144
tests/fw/util/test_stringlist.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/*
|
||||
* 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/stringlist.h"
|
||||
|
||||
#include "clar.h"
|
||||
|
||||
// Setup
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_stringlist__initialize(void) {
|
||||
}
|
||||
|
||||
void test_stringlist__cleanup(void) {
|
||||
}
|
||||
|
||||
// Tests
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
void test_stringlist__test(void) {
|
||||
StringList *list = malloc(20);
|
||||
memset(list, 0, 20);
|
||||
// no data
|
||||
list->serialized_byte_length = 0;
|
||||
cl_assert_equal_i(0, string_list_count(list));
|
||||
|
||||
list->serialized_byte_length = 3;
|
||||
// 4 empty strings
|
||||
cl_assert_equal_i(4, string_list_count(list));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 1));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 2));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 3));
|
||||
|
||||
// non-null-terminated string is treated as one string - this is the standard case
|
||||
// please note that the string will only be terminated if there's another \0 following
|
||||
// when deserializing the data, the deserializer will append the needed \0
|
||||
list->serialized_byte_length = 3;
|
||||
list->data[0] = 'a';
|
||||
list->data[1] = 'b';
|
||||
list->data[2] = 'c'; // end of data
|
||||
list->data[3] = 'd';
|
||||
list->data[4] = '\0';
|
||||
cl_assert_equal_i(1, string_list_count(list));
|
||||
cl_assert_equal_s("abcd", string_list_get_at(list, 0));
|
||||
|
||||
// 1 string (null terminated) => 2 strings, last is empty
|
||||
list->serialized_byte_length = 3;
|
||||
list->data[0] = 'a';
|
||||
list->data[1] = 'b';
|
||||
list->data[2] = '\0'; // end of data
|
||||
list->data[3] = '\0';
|
||||
cl_assert_equal_i(2, string_list_count(list));
|
||||
cl_assert_equal_s("ab", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 1));
|
||||
|
||||
// 2 strings (non-null terminated) - this is the standard case
|
||||
list->serialized_byte_length = 4;
|
||||
list->data[0] = 'a';
|
||||
list->data[1] = 'b';
|
||||
list->data[2] = '\0';
|
||||
list->data[3] = 'c'; // end of data
|
||||
list->data[4] = '\0';
|
||||
cl_assert_equal_i(2, string_list_count(list));
|
||||
cl_assert_equal_s("ab", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("c", string_list_get_at(list, 1));
|
||||
|
||||
// 3 strings (last two are is empty)
|
||||
list->serialized_byte_length = 4;
|
||||
list->data[0] = 'a';
|
||||
list->data[1] = 'b';
|
||||
list->data[2] = '\0';
|
||||
list->data[3] = '\0'; // end of data
|
||||
list->data[4] = '\0';
|
||||
cl_assert_equal_i(3, string_list_count(list));
|
||||
cl_assert_equal_s("ab", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 1));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 2));
|
||||
cl_assert_equal_s(NULL, string_list_get_at(list, 3));
|
||||
|
||||
// 4 strings (first and last two are empty)
|
||||
list->serialized_byte_length = 4;
|
||||
list->data[0] = '\0';
|
||||
list->data[1] = 'b';
|
||||
list->data[2] = '\0';
|
||||
list->data[3] = '\0'; // end of data
|
||||
list->data[4] = '\0';
|
||||
cl_assert_equal_i(4, string_list_count(list));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("b", string_list_get_at(list, 1));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 2));
|
||||
cl_assert_equal_s("", string_list_get_at(list, 3));
|
||||
|
||||
// 2 strings (last is not terminated and will fall through) will return 2 strings
|
||||
// when deserializing, the deserializer puts a \0 at the end
|
||||
// this case demonstrates the problem with incorrectly initialized data
|
||||
list->serialized_byte_length = 3;
|
||||
list->data[0] = 'a';
|
||||
list->data[1] = '\0';
|
||||
list->data[2] = 'b'; // end of data
|
||||
list->data[3] = 'c';
|
||||
list->data[4] = '\0';
|
||||
cl_assert_equal_i(2, string_list_count(list));
|
||||
cl_assert_equal_s("a", string_list_get_at(list, 0));
|
||||
cl_assert_equal_s("bc", string_list_get_at(list, 1));
|
||||
|
||||
// add a string to an empty string list
|
||||
list->serialized_byte_length = 0;
|
||||
string_list_add_string(list, 20, "hello", 10);
|
||||
cl_assert_equal_i(5, list->serialized_byte_length);
|
||||
cl_assert_equal_i(1, string_list_count(list));
|
||||
cl_assert_equal_s("hello", string_list_get_at(list, 0));
|
||||
|
||||
// add a string to string list with strings
|
||||
string_list_add_string(list, 20, "world", 10);
|
||||
cl_assert_equal_i(11, list->serialized_byte_length);
|
||||
cl_assert_equal_i(2, string_list_count(list));
|
||||
cl_assert_equal_s("world", string_list_get_at(list, 1));
|
||||
|
||||
// truncated because of the max string size
|
||||
string_list_add_string(list, 20, "foobar", 3);
|
||||
cl_assert_equal_i(15, list->serialized_byte_length);
|
||||
cl_assert_equal_i(3, string_list_count(list));
|
||||
cl_assert_equal_s("foo", string_list_get_at(list, 2));
|
||||
|
||||
// truncated because of the max list size
|
||||
string_list_add_string(list, 20, "abc", 10);
|
||||
cl_assert_equal_i(17, list->serialized_byte_length);
|
||||
cl_assert_equal_i(4, string_list_count(list));
|
||||
cl_assert_equal_s("a", string_list_get_at(list, 3));
|
||||
}
|
82
tests/fw/util/test_time.c
Normal file
82
tests/fw/util/test_time.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* 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/time/time.h"
|
||||
|
||||
#include <clar.h>
|
||||
|
||||
// Fakes
|
||||
///////////////////////////////////////////////////////////
|
||||
#include "../../fakes/fake_rtc.h"
|
||||
|
||||
// Overrides
|
||||
///////////////////////////////////////////////////////////
|
||||
int16_t clock_get_timezone_region_id(void) {
|
||||
return rtc_get_timezone_id();
|
||||
}
|
||||
|
||||
void clock_set_timezone_by_region_id(uint16_t region_id) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Tests
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
void test_time__initialize(void) {
|
||||
}
|
||||
|
||||
void test_time__cleanup(void) {
|
||||
}
|
||||
|
||||
void test_time__serial_distance32(void) {
|
||||
uint32_t day, hour, minute, second;
|
||||
|
||||
{
|
||||
time_util_split_seconds_into_parts(1, &day, &hour, &minute, &second);
|
||||
cl_assert_equal_i(day, 0);
|
||||
cl_assert_equal_i(hour, 0);
|
||||
cl_assert_equal_i(minute, 0);
|
||||
cl_assert_equal_i(second, 1);
|
||||
}
|
||||
|
||||
{
|
||||
time_util_split_seconds_into_parts(61, &day, &hour, &minute, &second);
|
||||
cl_assert_equal_i(day, 0);
|
||||
cl_assert_equal_i(hour, 0);
|
||||
cl_assert_equal_i(minute, 1);
|
||||
cl_assert_equal_i(second, 1);
|
||||
}
|
||||
|
||||
{
|
||||
second = 1;
|
||||
|
||||
time_util_split_seconds_into_parts((3 * (24 * 60 * 60)), &day, &hour, &minute, &second);
|
||||
cl_assert_equal_i(day, 3);
|
||||
cl_assert_equal_i(hour, 0);
|
||||
cl_assert_equal_i(minute, 0);
|
||||
cl_assert_equal_i(second, 0);
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
time_util_split_seconds_into_parts((3 * (24 * 60 * 60)) + (2 * (60 * 60)) + (4 * 60) + 5, &day, &hour, &minute, &second);
|
||||
cl_assert_equal_i(day, 3);
|
||||
cl_assert_equal_i(hour, 2);
|
||||
cl_assert_equal_i(minute, 4);
|
||||
cl_assert_equal_i(second, 5);
|
||||
}
|
||||
|
||||
}
|
77
tests/fw/util/wscript
Normal file
77
tests/fw/util/wscript
Normal file
|
@ -0,0 +1,77 @@
|
|||
from waftools.pebble_test import clar
|
||||
|
||||
def build(ctx):
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/base64.c",
|
||||
test_sources_ant_glob = "test_base64.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/shared_circular_buffer.c",
|
||||
test_sources_ant_glob = "test_shared_circular_buffer.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = " src/fw/util/time/time.c" \
|
||||
" src/fw/util/time/mktime.c" \
|
||||
" tests/fakes/fake_rtc.c",
|
||||
test_sources_ant_glob = "test_time.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/dict.c",
|
||||
test_sources_ant_glob = "test_dict.c")
|
||||
|
||||
#clar(ctx,
|
||||
# sources_ant_glob = "src/fw/util/mktime.c",
|
||||
# test_sources_ant_glob = "test_mktime.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/buffer.c",
|
||||
test_sources_ant_glob = "test_buffer.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/lru_cache.c",
|
||||
test_sources_ant_glob = "test_lru_cache.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/mbuf.c src/fw/util/mbuf_iterator.c",
|
||||
test_sources_ant_glob = "test_mbuf.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/rand/rand.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c",
|
||||
test_sources_ant_glob = "test_rand.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/stats.c",
|
||||
test_sources_ant_glob = "test_stats.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob='src/fw/util/legacy_checksum.c',
|
||||
test_sources_ant_glob='test_legacy_checksum.c')
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = " src/fw/util/rand/rand.c" \
|
||||
" src/fw/util/generic_attribute.c" \
|
||||
" src/fw/vendor/tinymt32/tinymt32.c",
|
||||
test_sources_ant_glob = "test_generic_attribute.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/hdlc.c",
|
||||
test_sources_ant_glob = "test_hdlc.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/stringlist.c",
|
||||
test_sources_ant_glob = "test_stringlist.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/pstring.c",
|
||||
test_sources_ant_glob = "test_pstring.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/ihex.c",
|
||||
test_sources_ant_glob = "test_ihex.c")
|
||||
|
||||
clar(ctx,
|
||||
sources_ant_glob = "src/fw/util/sle.c",
|
||||
test_sources_ant_glob = "test_sle.c")
|
||||
|
||||
# vim:filetype=python
|
Loading…
Add table
Add a link
Reference in a new issue