Import of the watch repository from Pebble

This commit is contained in:
Matthieu Jeanson 2024-12-12 16:43:03 -08:00 committed by Katharine Berry
commit 3b92768480
10334 changed files with 2564465 additions and 0 deletions

View file

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

View file

@ -0,0 +1,156 @@
/*
* Copyright 2024 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "util/circular_cache.h"
#include "util/size.h"
#include "clar.h"
#include <string.h>
#define NUM_TEST_ITEMS (3)
typedef struct {
int id;
bool *freed;
} TestCacheItem;
// Stubs
static bool s_free_flags[NUM_TEST_ITEMS];
static CircularCache s_test_cache;
static TestCacheItem s_cache_buffer[NUM_TEST_ITEMS];
static TestCacheItem s_test_item[NUM_TEST_ITEMS] = {
{ .id = 1, .freed = &s_free_flags[0] },
{ .id = 2, .freed = &s_free_flags[1] },
{ .id = 3, .freed = &s_free_flags[2] },
};
static const TestCacheItem ZERO_ITEM = {};
static void prv_destructor(void *item) {
if (((TestCacheItem *)item)->freed) {
*((TestCacheItem *)item)->freed = true;
}
}
static int prv_comparator(void *a, void *b) {
return ((TestCacheItem *)a)->id - ((TestCacheItem *)b)->id;
}
// setup and teardown
void test_circular_cache__initialize(void) {
memset(s_cache_buffer, 0, sizeof(s_cache_buffer));
circular_cache_init(&s_test_cache, (uint8_t *)s_cache_buffer, sizeof(TestCacheItem),
NUM_TEST_ITEMS, prv_comparator);
for (int i = 0; i < ARRAY_LENGTH(s_test_item); i++) {
s_free_flags[i] = false;
}
}
void test_circular_cache__cleanup(void) {
}
// tests
void test_circular_cache__push(void) {
circular_cache_set_item_destructor(&s_test_cache, prv_destructor);
circular_cache_push(&s_test_cache, &s_test_item[0]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[0], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &ZERO_ITEM, sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &ZERO_ITEM, sizeof(TestCacheItem));
circular_cache_push(&s_test_cache, &s_test_item[2]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[0], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &s_test_item[2], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &ZERO_ITEM, sizeof(TestCacheItem));
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[0], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &s_test_item[2], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &s_test_item[1], sizeof(TestCacheItem));
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[1], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &s_test_item[2], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &s_test_item[1], sizeof(TestCacheItem));
cl_assert(*s_test_item[0].freed);
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[1], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &s_test_item[1], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &s_test_item[1], sizeof(TestCacheItem));
cl_assert(*s_test_item[2].freed);
}
void test_circular_cache__get(void) {
cl_assert(!circular_cache_get(&s_test_cache, &s_test_item[0]));
cl_assert(!circular_cache_get(&s_test_cache, &s_test_item[1]));
cl_assert(!circular_cache_get(&s_test_cache, &s_test_item[2]));
circular_cache_push(&s_test_cache, &s_test_item[0]);
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert(!circular_cache_get(&s_test_cache, &s_test_item[2]));
cl_assert_equal_p(circular_cache_get(&s_test_cache, &s_test_item[0]), &s_cache_buffer[0]);
cl_assert_equal_p(circular_cache_get(&s_test_cache, &s_test_item[1]), &s_cache_buffer[1]);
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert(!circular_cache_get(&s_test_cache, &s_test_item[2]));
cl_assert_equal_p(circular_cache_get(&s_test_cache, &s_test_item[1]), &s_cache_buffer[1]);
}
void test_circular_cache__contains(void) {
cl_assert(!circular_cache_contains(&s_test_cache, &s_test_item[0]));
cl_assert(!circular_cache_contains(&s_test_cache, &s_test_item[1]));
cl_assert(!circular_cache_contains(&s_test_cache, &s_test_item[2]));
circular_cache_push(&s_test_cache, &s_test_item[0]);
circular_cache_push(&s_test_cache, &s_test_item[1]);
cl_assert(!circular_cache_contains(&s_test_cache, &s_test_item[2]));
cl_assert(circular_cache_contains(&s_test_cache, &s_test_item[0]));
cl_assert(circular_cache_contains(&s_test_cache, &s_test_item[1]));
}
void test_circular_cache__fill(void) {
circular_cache_fill(&s_test_cache, (uint8_t *)&s_test_item[1]);
cl_assert_equal_m(&s_cache_buffer[0], &s_test_item[1], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[1], &s_test_item[1], sizeof(TestCacheItem));
cl_assert_equal_m(&s_cache_buffer[2], &s_test_item[1], sizeof(TestCacheItem));
}
void test_circular_cache__flush(void) {
circular_cache_set_item_destructor(&s_test_cache, prv_destructor);
circular_cache_push(&s_test_cache, &s_test_item[0]);
circular_cache_flush(&s_test_cache);
cl_assert(*s_test_item[0].freed);
cl_assert(!(*s_test_item[1].freed));
cl_assert(!(*s_test_item[2].freed));
memset(s_cache_buffer, 0, sizeof(s_cache_buffer));
*s_test_item[0].freed = false;
circular_cache_push(&s_test_cache, &s_test_item[0]);
circular_cache_push(&s_test_cache, &s_test_item[1]);
circular_cache_push(&s_test_cache, &s_test_item[2]);
circular_cache_flush(&s_test_cache);
cl_assert(*s_test_item[0].freed);
cl_assert(*s_test_item[1].freed);
cl_assert(*s_test_item[2].freed);
}

View file

@ -0,0 +1,86 @@
/*
* 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/crc32.h"
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#define assert_equal_hex(A, B) \
do { \
uint32_t a = (A); \
uint32_t b = (B); \
if (a != b) { \
char error_msg[256]; \
sprintf(error_msg, \
"%#08"PRIx32" != %#08"PRIx32"\n", \
a, b); \
clar__assert(0, __FILE__, __LINE__, \
#A " != " #B, error_msg, 1); \
} \
} while (0)
static uint32_t crc;
void test_crc32__initialize(void) {
crc = crc32(0, NULL, 0);
}
void test_crc32__initial_value_matches_header(void) {
cl_assert_equal_i(crc, CRC32_INIT);
}
void test_crc32__null(void) {
cl_assert_equal_i(crc, 0);
}
void test_crc32__empty_buffer(void) {
crc = crc32(crc, "arbitrary pointer", 0);
assert_equal_hex(crc, 0);
}
void test_crc32__one_byte(void) {
crc = crc32(crc, "abcdefg", 1);
assert_equal_hex(crc, 0xe8b7be43);
}
void test_crc32__standard_check(void) {
// "Check" value from "A Painless Guide to CRC Error Detection Algorithms"
crc = crc32(crc, "123456789", 9);
assert_equal_hex(crc, 0xCBF43926);
}
void test_crc32__residue(void) {
uint8_t message[30];
memcpy(message, "1234567890", 10);
crc = crc32(crc, message, 10);
message[10] = crc & 0xff;
message[11] = (crc >> 8) & 0xff;
message[12] = (crc >> 16) & 0xff;
message[13] = (crc >> 24) & 0xff;
assert_equal_hex(crc32(crc32(0, NULL, 0), message, 14), CRC32_RESIDUE);
}
void test_crc32__null_residue(void) {
uint8_t data[4] = {0, 0, 0, 0};
crc = crc32(crc, data, 4);
assert_equal_hex(crc, CRC32_RESIDUE);
}

View file

@ -0,0 +1,182 @@
/*
* 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/keyed_circular_cache.h"
#include "util/size.h"
#include "clar.h"
#include <string.h>
#define TEST_BUFFER_SIZE (3)
typedef struct {
uint32_t data[4];
} TestCacheItem;
typedef struct {
uint32_t key;
TestCacheItem item;
} TestCacheDefinition;
static KeyedCircularCache s_test_cache;
static KeyedCircularCacheKey s_cache_keys[TEST_BUFFER_SIZE];
static TestCacheItem s_cache_buffer[TEST_BUFFER_SIZE];
static TestCacheItem ZERO_ITEM = {};
static const TestCacheDefinition s_test_data[] = {
{ .key = 0x12345678,
.item = { .data = { 0xDEADCAFE, 0xBEEFBABE, 0xF00DD00D, 0xDEFACED1, }, },
},
{ .key = 0x9ABCDEF0,
.item = { .data = { 0x13579BDF, 0x02468ACE, 0xFEDCBA98, 0x76543210, }, },
},
{ .key = 0x01238ACE,
.item = { .data = { 0x012389AB, 0x4567CDEF, 0x014589CD, 0x2367ABEF, }, },
},
{ .key = 0x45679BDF,
.item = { .data = { 0xFEDC7654, 0xBA983210, 0xFEBA7632, 0xDC985410, }, },
},
};
// setup and teardown
void test_keyed_circular_cache__initialize(void) {
memset(s_cache_buffer, 0, sizeof(s_cache_buffer));
memset(s_cache_keys, 0, sizeof(s_cache_keys));
keyed_circular_cache_init(&s_test_cache, s_cache_keys, s_cache_buffer, sizeof(TestCacheItem),
TEST_BUFFER_SIZE);
}
void test_keyed_circular_cache__cleanup(void) {
}
// tests
static void prv_push(int index) {
keyed_circular_cache_push(&s_test_cache, s_test_data[index].key, &s_test_data[index].item);
}
static TestCacheItem *prv_get(KeyedCircularCacheKey key) {
return keyed_circular_cache_get(&s_test_cache, key);
}
static void prv_test_backing_data(int cache_idx, int data_idx) {
cl_assert_equal_i(s_cache_keys[cache_idx], s_test_data[data_idx].key);
cl_assert_equal_m(&s_cache_buffer[cache_idx], &s_test_data[data_idx].item,
sizeof(TestCacheItem));
}
static void prv_test_backing_data_empty(int cache_idx) {
cl_assert_equal_i(s_cache_keys[cache_idx], 0);
cl_assert_equal_m(&s_cache_buffer[cache_idx], &ZERO_ITEM, sizeof(TestCacheItem));
}
static void prv_test_get_miss(int data_idx) {
cl_assert(!prv_get(s_test_data[data_idx].key));
}
static void prv_test_get_hit(int data_idx, int cache_idx) {
TestCacheItem *data = prv_get(s_test_data[data_idx].key);
cl_assert(data);
cl_assert_equal_m(data, &s_test_data[data_idx].item, sizeof(TestCacheItem));
cl_assert(data == &s_cache_buffer[cache_idx]);
}
void test_keyed_circular_cache__push(void) {
prv_push(0);
prv_test_backing_data(0, 0);
prv_test_backing_data_empty(1);
prv_test_backing_data_empty(2);
prv_push(1);
prv_test_backing_data(0, 0);
prv_test_backing_data(1, 1);
prv_test_backing_data_empty(2);
prv_push(2);
prv_test_backing_data(0, 0);
prv_test_backing_data(1, 1);
prv_test_backing_data(2, 2);
prv_push(3);
prv_test_backing_data(0, 3);
prv_test_backing_data(1, 1);
prv_test_backing_data(2, 2);
prv_push(0);
prv_test_backing_data(0, 3);
prv_test_backing_data(1, 0);
prv_test_backing_data(2, 2);
prv_push(1);
prv_test_backing_data(0, 3);
prv_test_backing_data(1, 0);
prv_test_backing_data(2, 1);
}
void test_circular_cache__get(void) {
prv_test_get_miss(0);
prv_test_get_miss(1);
prv_test_get_miss(2);
prv_test_get_miss(3);
prv_push(0);
prv_test_get_hit(0, 0);
prv_test_get_miss(1);
prv_test_get_miss(2);
prv_test_get_miss(3);
prv_push(1);
prv_test_get_hit(0, 0);
prv_test_get_hit(1, 1);
prv_test_get_miss(2);
prv_test_get_miss(3);
prv_push(2);
prv_test_get_hit(0, 0);
prv_test_get_hit(1, 1);
prv_test_get_hit(2, 2);
prv_test_get_miss(3);
prv_push(3);
prv_test_get_miss(0);
prv_test_get_hit(1, 1);
prv_test_get_hit(2, 2);
prv_test_get_hit(3, 0);
prv_push(2);
prv_test_get_miss(0);
prv_test_get_miss(1);
prv_test_get_hit(2, 1);
prv_test_get_hit(3, 0);
prv_push(0);
prv_test_get_hit(0, 2);
prv_test_get_miss(1);
prv_test_get_hit(2, 1);
prv_test_get_hit(3, 0);
prv_push(1);
prv_test_get_hit(0, 2);
prv_test_get_hit(1, 0);
prv_test_get_hit(2, 1);
prv_test_get_miss(3);
prv_push(3);
prv_test_get_hit(0, 2);
prv_test_get_hit(1, 0);
prv_test_get_miss(2);
prv_test_get_hit(3, 1);
}

282
tests/libutil/test_list.c Normal file
View file

@ -0,0 +1,282 @@
/*
* 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/list.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(int level, const char* src_filename, int src_line_number, const char* fmt, ...) { }
// Tests
///////////////////////////////////////////////////////////
void test_list__initialize(void) {
}
void test_list__cleanup(void) {
}
void test_list__insert_after(void) {
ListNode *tail = NULL;
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL;
tail = list_insert_after(tail, &a);
cl_assert(tail == &a);
tail = list_insert_after(&a, &b);
cl_assert(tail == &b);
}
void test_list__insert_before(void) {
ListNode *head = NULL;
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL;
head = list_insert_before(head, &a);
cl_assert(head == &a);
head = list_insert_before(&b, &a);
cl_assert(head == &a);
}
void test_list__pop_head(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL;
list_insert_after(&a, &b);
ListNode *new_head = list_pop_head(&b);
cl_assert(new_head == &b);
cl_assert(list_get_next(&a) == NULL);
cl_assert(list_get_head(&b) == &b);
}
void test_list__pop_tail(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL;
list_insert_after(&a, &b);
ListNode *new_tail = list_pop_tail(&a);
cl_assert(new_tail == &a);
cl_assert(list_get_prev(&b) == NULL);
cl_assert(list_get_tail(&b) == &b);
}
void test_list__append(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL;
ListNode *tail;
tail = list_append(&a, &b);
cl_assert(tail == &b);
tail = list_append(&a, &c);
cl_assert(tail == &c);
cl_assert(list_get_prev(&a) == NULL);
cl_assert(list_get_next(&a) == &b);
cl_assert(list_get_prev(&b) == &a);
cl_assert(list_get_next(&b) == &c);
cl_assert(list_get_prev(&c) == &b);
cl_assert(list_get_next(&c) == NULL);
}
void test_list__prepend(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL;
ListNode *head;
head = list_prepend(&c, &b);
cl_assert(head == &b);
head = list_prepend(&b, &a);
cl_assert(head == &a);
cl_assert(list_get_prev(&a) == NULL);
cl_assert(list_get_next(&a) == &b);
cl_assert(list_get_prev(&b) == &a);
cl_assert(list_get_next(&b) == &c);
cl_assert(list_get_prev(&c) == &b);
cl_assert(list_get_next(&c) == NULL);
}
void test_list__count(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL;
ListNode *tail = list_append(list_append(&a, &b), &c);
cl_assert(list_count(tail) == 3);
cl_assert(list_count(&a) == 3);
cl_assert(list_count(&b) == 3);
cl_assert(list_count(&c) == 3);
cl_assert(list_count_to_tail_from(&a) == 3);
cl_assert(list_count_to_tail_from(&b) == 2);
cl_assert(list_count_to_tail_from(&c) == 1);
cl_assert(list_count_to_head_from(&c) == 3);
cl_assert(list_count_to_head_from(&b) == 2);
cl_assert(list_count_to_head_from(&a) == 1);
}
typedef struct IntNode {
ListNode list_node;
int value;
} IntNode;
int sorting_comparator(IntNode* a, IntNode* b) {
return b->value - a->value;
}
void test_list__sort_ascending(void) {
IntNode bar1 = { .value = 1 };
IntNode bar2 = { .value = 2 };
IntNode bar3 = { .value = 3 };
ListNode* head = 0;
head = list_sorted_add(head, &bar2.list_node, (Comparator) sorting_comparator, true);
cl_assert(head == &bar2.list_node);
head = list_sorted_add(head, &bar3.list_node, (Comparator) sorting_comparator, true);
cl_assert(head == &bar2.list_node);
cl_assert(list_get_tail(head) == &bar3.list_node);
head = list_sorted_add(head, &bar1.list_node, (Comparator) sorting_comparator, true);
cl_assert(head == &bar1.list_node);
cl_assert(list_get_next(head) == &bar2.list_node);
cl_assert(list_get_tail(head) == &bar3.list_node);
}
void test_list__sort_descending(void) {
IntNode bar1 = { .value = 1 };
IntNode bar2 = { .value = 2 };
IntNode bar3 = { .value = 3 };
ListNode* head = 0;
head = list_sorted_add(head, &bar2.list_node, (Comparator) sorting_comparator, false);
cl_assert(head == &bar2.list_node);
head = list_sorted_add(head, &bar3.list_node, (Comparator) sorting_comparator, false);
cl_assert(head == &bar3.list_node);
cl_assert(list_get_tail(head) == &bar2.list_node);
head = list_sorted_add(head, &bar1.list_node, (Comparator) sorting_comparator, false);
cl_assert(head == &bar3.list_node);
cl_assert(list_get_next(head) == &bar2.list_node);
cl_assert(list_get_tail(head) == &bar1.list_node);
}
static bool is_odd(IntNode *node, void *data) {
return (node->value & 1);
(void)data;
}
static bool is_even(IntNode *node, void *data) {
return ((node->value & 1) == 0);
(void)data;
}
void test_list__find_next_and_prev(void) {
IntNode bar[5] = {0};
ListNode* tail = NULL;
for (int i = 0; i < 5; ++i) {
bar[i].value = i;
tail = list_append(tail, &bar[i].list_node);
}
bool(*filter_odd)(ListNode*, void *) = (bool(*)(ListNode*, void *)) is_odd;
bool(*filter_even)(ListNode*, void *) = (bool(*)(ListNode*, void *)) is_even;
// Find next odd one after '2':
cl_assert(list_find_next(&bar[2].list_node, filter_odd, false, NULL) == &bar[3].list_node);
// 5 is the last odd number, so NULL is next:
cl_assert(list_find_next(&bar[4].list_node, filter_odd, false, NULL) == NULL);
// Test wrap around, find '1' after '4':
cl_assert(list_find_next(&bar[4].list_node, filter_odd, true, NULL) == &bar[1].list_node);
// Test wrap around matching first item, find '0' after '4':
cl_assert(list_find_next(&bar[4].list_node, filter_even, true, NULL) == &bar[0].list_node);
// Find prev odd one before '2':
cl_assert(list_find_prev(&bar[2].list_node, filter_odd, false, NULL) == &bar[1].list_node);
// '1' is the first odd number, so NULL is prev:
cl_assert(list_find_prev(&bar[1].list_node, filter_odd, false, NULL) == NULL);
// Test wrap around, find '3' before '0':
cl_assert(list_find_prev(&bar[0].list_node, filter_odd, true, NULL) == &bar[3].list_node);
// Test wrap around matching last item, find '4' before '0':
cl_assert(list_find_prev(&bar[0].list_node, filter_even, true, NULL) == &bar[4].list_node);
// Make everything even:
for (int i = 0; i < 5; ++i) {
bar[i].value = i * 2;
}
// Wrap around once, find nothing and return NULL:
cl_assert(list_find_next(&bar[3].list_node, (bool(*)(ListNode*, void*))is_odd, true, NULL) == NULL);
cl_assert(list_find_prev(&bar[3].list_node, (bool(*)(ListNode*, void*))is_odd, true, NULL) == NULL);
// Test NULL starting node:
cl_assert(list_find_next(NULL, filter_odd, false, NULL) == NULL);
cl_assert(list_find_prev(NULL, filter_odd, false, NULL) == NULL);
}
void test_list__concatenate(void) {
ListNode a = LIST_NODE_NULL, b = LIST_NODE_NULL, c = LIST_NODE_NULL;
ListNode d = LIST_NODE_NULL, e = LIST_NODE_NULL, f = LIST_NODE_NULL;
cl_assert_equal_p(list_concatenate(&a, &b), &a);
cl_assert_equal_p(a.next, &b);
cl_assert_equal_p(b.prev, &a);
cl_assert_equal_p(list_concatenate(&b, &c), &a);
cl_assert_equal_p(b.next, &c);
cl_assert_equal_p(c.prev, &b);
cl_assert_equal_p(list_concatenate(&e, &f), &e);
cl_assert_equal_p(list_concatenate(&d, &f), &d);
cl_assert_equal_p(list_concatenate(&f, &d), &d);
cl_assert_equal_p(list_concatenate(NULL, &d), &d);
cl_assert_equal_p(list_concatenate(NULL, &f), &d);
cl_assert_equal_p(list_concatenate(&f, NULL), &d);
cl_assert_equal_p(list_concatenate(&d, NULL), &d);
cl_assert_equal_p(list_concatenate(&a, &d), &a);
cl_assert_equal_p(list_get_head(&e), &a);
cl_assert_equal_p(list_get_tail(&b), &f);
c.next = NULL;
d.prev = NULL;
cl_assert_equal_p(list_concatenate(&c, &f), &a);
cl_assert_equal_p(list_get_head(&e), &a);
cl_assert_equal_p(list_get_tail(&b), &f);
}
#define CTX_VALUE 0xdeadbeef
#define INT_VALUE 17
static bool prv_list_set_val_each(ListNode *node, void *context) {
IntNode *int_node = (IntNode *)node;
int_node->value = INT_VALUE;
cl_assert_equal_i(CTX_VALUE, (uintptr_t) context);
return true;
}
void test_list__each(void) {
IntNode a = {}, b = {}, c = {};
ListNode *head;
head = list_prepend((ListNode *)&c, (ListNode *)&b);
head = list_prepend((ListNode *)&b, (ListNode *)&a);
cl_assert_equal_i(list_count((ListNode *)head), 3);
list_foreach(head, prv_list_set_val_each, (void *)(uintptr_t)CTX_VALUE);
uint32_t num_nodes = 0;
ListNode *temp = head;
while (temp) {
ListNode *next = temp->next;
IntNode *int_node = (IntNode *)temp;
cl_assert_equal_i(int_node->value, INT_VALUE);
temp = next;
num_nodes++;
}
cl_assert_equal_i(num_nodes, 3);
}

281
tests/libutil/test_math.c Normal file
View file

@ -0,0 +1,281 @@
/*
* 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/trig.h"
#include "util/math.h"
#include <math.h>
#include <inttypes.h>
#include <stdio.h>
#include <clar.h>
// Stubs
///////////////////////////////////////////////////////////
#include "stubs_logging.h"
#include "stubs_pbl_malloc.h"
#include "stubs_passert.h"
// Tests
///////////////////////////////////////////////////////////
static void check_atan2(int16_t x, int16_t y) {
int32_t ours = atan2_lookup(y, x) * 180 / TRIG_PI;
double theirs = atan2(y, x) / 3.14159 * 180;
// atan2 returns in range [-pi, +pi], but we have [0,2pi].
if (theirs < 0) theirs += 360;
cl_assert(abs(ours - (int) theirs) < 3); // Allow 3 degrees difference max
}
static double log_two(uint32_t n) {
return (log(n) / log(2));
}
static void check_ceil_log_two(uint32_t n) {
int ours = ceil_log_two(n);
int theirs = ceil(log_two(n));
cl_assert(ours == theirs);
}
void test_math__initialize(void) {
}
void test_math__cleanup(void) {
}
void test_math__atan2(void) {
check_atan2(10, 14);
check_atan2(3, 5);
check_atan2(5, 3);
check_atan2(10, 10);
check_atan2(-153, 217);
check_atan2(-28, -133);
check_atan2(323, -229);
check_atan2(245, 196);
check_atan2(65, -3);
check_atan2(331, -320);
check_atan2(-151, 284);
check_atan2(111, -98);
check_atan2(-44, -17);
check_atan2(269, -356);
check_atan2(-78, 268);
check_atan2(-247, 37);
check_atan2(-119, 33);
check_atan2(234, -253);
check_atan2(355, -193);
check_atan2(-6, -310);
check_atan2(15, -19);
check_atan2(34, -32);
check_atan2(-158, 299);
check_atan2(120, 102);
check_atan2(0, 0);
check_atan2(0, 10);
check_atan2(10, 0);
check_atan2(-32768, 1); // <- causes overflow for int16
check_atan2(1, -32768); // <- causes overflow for int16
check_atan2(20001, 20000); // <- causes overflow if numbers are added in an int16
check_atan2(32767, 1);
check_atan2(1, 32767);
check_atan2(32767, 0);
check_atan2(0, 32767);
check_atan2(23400, -25300);
check_atan2(30500, -1930);
check_atan2(-6, -310);
check_atan2(15000, -19);
check_atan2(34, -3200);
check_atan2(-1508, 299);
check_atan2(1020, 1002);
}
void test_math__ceil_log_two(void) {
check_ceil_log_two(4);
check_ceil_log_two(5);
check_ceil_log_two(100);
check_ceil_log_two(256);
check_ceil_log_two(123456);
}
void test_math__sign_extend(void) {
cl_assert_equal_i(sign_extend(0, 32), 0);
cl_assert_equal_i(sign_extend(0, 3), 0);
cl_assert_equal_i(sign_extend(1, 32), 1);
cl_assert_equal_i(sign_extend(1, 3), 1);
cl_assert_equal_i(sign_extend(-1, 32), -1);
cl_assert_equal_i(sign_extend(-1, 3), -1);
cl_assert_equal_i(sign_extend(7, 32), 7);
cl_assert_equal_i(sign_extend(7, 3), -1);
}
void test_math__serial_distance32(void) {
{
int32_t dist = serial_distance32(0x0, 0x1);
cl_assert_equal_i(dist, 1);
}
{
int32_t dist = serial_distance32(0x1, 0x0);
cl_assert_equal_i(dist, -1);
}
{
int32_t dist = serial_distance32(0x0, 0xffffffff);
cl_assert_equal_i(dist, -1);
}
{
int32_t dist = serial_distance32(0xffffffff, 0x0);
cl_assert_equal_i(dist, 1);
}
{
int32_t dist = serial_distance32(0x0, 0x7fffffff);
cl_assert_equal_i(dist, 0x7fffffff);
}
}
void test_math__serial_distance3(void) {
{
int32_t dist = serial_distance(0, 1, 3);
cl_assert_equal_i(dist, 1);
}
{
int32_t dist = serial_distance(1, 0, 3);
cl_assert_equal_i(dist, -1);
}
{
int32_t dist = serial_distance(0, 7, 3);
cl_assert_equal_i(dist, -1);
}
{
int32_t dist = serial_distance(7, 0, 3);
cl_assert_equal_i(dist, 1);
}
{
int32_t dist = serial_distance(6, 0, 3);
cl_assert_equal_i(dist, 2);
}
{
int32_t dist = serial_distance(7, 1, 3);
cl_assert_equal_i(dist, 2);
}
{
int32_t dist = serial_distance(6, 1, 3);
cl_assert_equal_i(dist, 3);
}
}
void test_math__is_signed_macro(void) {
cl_assert(IS_SIGNED((int)-1) == true);
cl_assert(IS_SIGNED((unsigned int)1) == false);
}
void test_math__test_within_macro(void) {
int16_t min;
int16_t max;
// Min and max are both positive
////////////////////////////////
min = 5;
max = 10;
// Min and max themselves should satisfy WITHIN
cl_assert_equal_b(WITHIN(min, min, max), true);
cl_assert_equal_b(WITHIN(max, min, max), true);
// In the middle of the bounds
cl_assert_equal_b(WITHIN(7, min, max), true);
// Just out of bounds
cl_assert_equal_b(WITHIN(4, min, max), false);
cl_assert_equal_b(WITHIN(11, min, max), false);
// Negative out of bounds
cl_assert_equal_i(WITHIN(-5, min, max), false);
// Positive out of bounds
cl_assert_equal_i(WITHIN(0, min, max), false);
// Min negative, max positive
////////////////////////////////
min = -10;
max = 10;
// Min and max themselves should satisfy WITHIN
cl_assert_equal_b(WITHIN(min, min, max), true);
cl_assert_equal_b(WITHIN(max, min, max), true);
// In the middle of the bounds
cl_assert_equal_i(WITHIN(-5, min, max), true);
cl_assert_equal_i(WITHIN(0, min, max), true);
cl_assert_equal_i(WITHIN(5, min, max), true);
// Just out of bounds
cl_assert_equal_i(WITHIN(-11, min, max), false);
cl_assert_equal_i(WITHIN(11, min, max), false);
// Min and max are both negative
////////////////////////////////
min = -20;
max = -10;
// Min and max themselves should satisfy WITHIN
cl_assert_equal_b(WITHIN(min, min, max), true);
cl_assert_equal_b(WITHIN(max, min, max), true);
// In the middle of the bounds
cl_assert_equal_i(WITHIN(-15, min, max), true);
// Just out of bounds
cl_assert_equal_i(WITHIN(-21, min, max), false);
cl_assert_equal_i(WITHIN(-9, min, max), false);
// Positive out of bounds
cl_assert_equal_i(WITHIN(0, min, max), false);
cl_assert_equal_i(WITHIN(5, min, max), false);
}
void test_math__distance_to_boundary(void) {
cl_assert_equal_i(10, distance_to_mod_boundary(10, 100));
cl_assert_equal_i(50, distance_to_mod_boundary(50, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(90, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(110, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(210, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(-10, 100));
cl_assert_equal_i(50, distance_to_mod_boundary(-50, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(-90, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(-110, 100));
cl_assert_equal_i(10, distance_to_mod_boundary(-210, 100));
}
void test_math__gcd_zero(void) {
cl_assert_equal_i(0, gcd(0, 0));
}
void test_math__gcd_coprime(void) {
cl_assert_equal_i(1, gcd(8, 27));
}
void test_math__gcd_basic(void) {
cl_assert_equal_i(9, gcd(9, 18));
}
void test_math__gcd_basic_reversed(void) {
cl_assert_equal_i(9, gcd(18, 9));
}
void test_math__gcd_of_number_and_itself(void) {
cl_assert_equal_i(10, gcd(10, 10));
}

View file

@ -0,0 +1,536 @@
/*
* 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/math_fixed.h"
#include "clar.h"
#include <stdio.h>
#include <string.h>
// Helper Functions
////////////////////////////////////
// Stubs
////////////////////////////////////
// Tests
////////////////////////////////////
////////////////////////////////////////////////////////////////
/// Fixed_S16_3 = 1 bit sign, 12 bits integer, 3 bits fraction
////////////////////////////////////////////////////////////////
void test_math_fixed__S16_3_create(void) {
Fixed_S16_3 num;
int16_t test_num;
cl_assert(FIXED_S16_3_PRECISION == 3);
int Fixed_S16_3_size = sizeof(Fixed_S16_3);
cl_assert(Fixed_S16_3_size == sizeof(int16_t));
test_num = 1 << FIXED_S16_3_PRECISION;
num = (Fixed_S16_3){ .integer = 1, .fraction = 0 };
// Test number creation
test_num = (int16_t)((float)1 * (1 << FIXED_S16_3_PRECISION));
cl_assert(num.raw_value == test_num);
cl_assert((FIXED_S16_3_ONE.raw_value == test_num));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
num = (Fixed_S16_3){ .raw_value = (int16_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
test_num = (int16_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
num = (Fixed_S16_3){ .raw_value = (int16_t)((float)-2 * (1 << FIXED_S16_3_PRECISION)) };
test_num = (int16_t)((float)-2 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
num = (Fixed_S16_3){ .raw_value = (int16_t)((float)-3.5 * (1 << FIXED_S16_3_PRECISION)) };
test_num = (int16_t)((float)-3.5 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
}
void test_math_fixed__S16_3_fraction(void) {
Fixed_S16_3 num;
int16_t test_num;
// This test shows how the values change across various fraction values
test_num = (int16_t)((float)-1.125 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -2);
cl_assert(num.fraction == 7);
// This confirms that the fixed number is (2^FIXED_S16_3_PRECISION)*(float value)
test_num = -9;
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
test_num = (int16_t)((float)-1 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 0);
test_num = (int16_t)((float)-0.875 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 1);
test_num = (int32_t)((float)-0.750 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 2);
test_num = (int32_t)((float)-0.625 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 3);
test_num = (int32_t)((float)-0.500 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 4);
test_num = (int32_t)((float)-0.375 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 5);
test_num = (int32_t)((float)-0.250 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 6);
test_num = (int32_t)((float)-0.125 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 7);
test_num = (int32_t)((float)-0 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 0);
test_num = (int32_t)((float)0 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 0);
test_num = (int32_t)((float)0.125 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 1);
test_num = (int32_t)((float)0.250 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 2);
test_num = (int32_t)((float)0.375 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 3);
test_num = (int32_t)((float)0.500 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 4);
test_num = (int32_t)((float)0.625 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 5);
test_num = (int32_t)((float)0.750 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 6);
test_num = (int32_t)((float)0.875 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 0);
cl_assert(num.fraction == 7);
test_num = (int16_t)((float)1 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 1);
cl_assert(num.fraction == 0);
test_num = (int16_t)((float)1.125 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 1);
cl_assert(num.fraction == 1);
}
void test_math_fixed__S16_3_range(void) {
Fixed_S16_3 num;
int16_t test_num;
// This equates to -0.125
num = (Fixed_S16_3){ .raw_value = 0xFFFF };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 7);
test_num = (int32_t)((float)-0.125 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
num.raw_value++;
cl_assert(num.integer == 0);
cl_assert(num.fraction == 0);
num = (Fixed_S16_3){ .raw_value = 0x8000 };
cl_assert(num.integer == -4096);
cl_assert(num.fraction == 0);
test_num = (int32_t)((float)-4096 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
// overflowing negatively from -4096 results in going to 4095.875
num.raw_value--;
cl_assert(num.integer == 4095);
cl_assert(num.fraction == 7);
num = (Fixed_S16_3){ .raw_value = 0x7FFF };
cl_assert(num.integer == 4095);
cl_assert(num.fraction == 7);
test_num = (int32_t)((float)4095.875 * (1 << FIXED_S16_3_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S16_3)) == 0);
// overflowing positively from 4095.875 results in going to -4096
num.raw_value++;
cl_assert(num.integer == -4096);
cl_assert(num.fraction == 0);
}
void test_math_fixed__Fixed_S16_3_rounded_int(void) {
cl_assert_equal_i(0, Fixed_S16_3_rounded_int(Fixed_S16_3(0)));
cl_assert_equal_i(0, Fixed_S16_3_rounded_int(Fixed_S16_3(3)));
cl_assert_equal_i(1, Fixed_S16_3_rounded_int(Fixed_S16_3(4)));
cl_assert_equal_i(1, Fixed_S16_3_rounded_int(Fixed_S16_3(8)));
cl_assert_equal_i(2, Fixed_S16_3_rounded_int(Fixed_S16_3(12)));
cl_assert_equal_i(0, Fixed_S16_3_rounded_int(Fixed_S16_3(-3)));
cl_assert_equal_i(-1, Fixed_S16_3_rounded_int(Fixed_S16_3(-4)));
cl_assert_equal_i(-1, Fixed_S16_3_rounded_int(Fixed_S16_3(-5)));
cl_assert_equal_i(-1, Fixed_S16_3_rounded_int(Fixed_S16_3(-8)));
cl_assert_equal_i(-2, Fixed_S16_3_rounded_int(Fixed_S16_3(-12)));
}
void test_math_fixed__S16_3_rounding(void) {
Fixed_S16_3 num;
int16_t test_num;
// This test shows how the in between fractional values evaluate to the fixed representation
// Positive numbers round down to nearest fraction
// Negative numbers round up to neareset fraction
test_num = (int16_t)((float)-1.249 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -2);
cl_assert(num.fraction == 7); // rounds up to -1.125
test_num = (int16_t)((float)-1.126 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -2);
cl_assert(num.fraction == 7); // rounds up to -1.125
test_num = (int16_t)((float)-1.124 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == -1);
cl_assert(num.fraction == 0); // rounds up to -1.000
test_num = (int16_t)((float)1.124 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 1);
cl_assert(num.fraction == 0); // rounds down to 1.000
test_num = (int16_t)((float)1.126 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 1);
cl_assert(num.fraction == 1); // rounds down to 1.125
test_num = (int16_t)((float)1.249 * (1 << FIXED_S16_3_PRECISION));
num = (Fixed_S16_3){ .raw_value = test_num };
cl_assert(num.integer == 1);
cl_assert(num.fraction == 1); // rounds down to 1.125
}
void test_math_fixed__S16_3_add(void) {
Fixed_S16_3 num1, num2;
Fixed_S16_3 sum, sum_c;
// Test number addition
num1 = FIXED_S16_3_ONE;
num2 = FIXED_S16_3_ONE;
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)2 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 3.5 + 1 = 4.5
num1 = (Fixed_S16_3){ .raw_value = (int16_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
num2 = FIXED_S16_3_ONE;
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)4.5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 1 + 3.5 = 4.5 - test commutative property of addition
num1 = FIXED_S16_3_ONE;
num2 = (Fixed_S16_3){ .raw_value = (int16_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)4.5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2 + -3 = -5
num1 = (Fixed_S16_3){ .raw_value = (int16_t)((float)-2 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S16_3){ .raw_value = (int16_t)((float)-3 * (1 << FIXED_S16_3_PRECISION)) };
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)-5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2 + 5 = 3
num1 = (Fixed_S16_3){ .raw_value = (int16_t)((float)-2 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S16_3){ .raw_value = (int16_t)((float)5 * (1 << FIXED_S16_3_PRECISION)) };
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)3 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2.1 + 5.4 ~= 3.375 (nearest 1/8 fraction to the expected result)
// math is as follows:
// -2.1 * (1 << 8) = -16.8 = -16 (drop fraction) ==> -2
// 5.4 * (1 << 8) = 43.2 = 43 (drop fraction) ==> 5.375
// -16 + 43 = 27 = 3.375 * (1 << 8)
num1 = (Fixed_S16_3){ .raw_value = (int16_t)((float)-2.1 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S16_3){ .raw_value = (int16_t)((float)5.4 * (1 << FIXED_S16_3_PRECISION)) };
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)3.375 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 2.1 - 5.4 ~= -3.375 (nearest 1/8 fraction to the expected result)
// math is as follows:
// 2.1 * (1 << 8) = 16.8 = 16 (drop fraction) ==> 2
// -5.4 * (1 << 8) = -43.2 = -43 (drop fraction) ==> -5.375
// 16 - 43 = -27 = -3.375 * (1 << 8)
num1 = (Fixed_S16_3){ .raw_value = (int16_t)((float)2.1 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S16_3){ .raw_value = (int16_t)((float)-5.4 * (1 << FIXED_S16_3_PRECISION)) };
sum = Fixed_S16_3_add(num1, num2);
sum_c = (Fixed_S16_3){ .raw_value = (int16_t)((float)-3.375 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
}
////////////////////////////////////////////////////////////////
/// Fixed_S32_16 = 1 bit sign, 15 bits integer, 16 bits fraction
////////////////////////////////////////////////////////////////
void test_math_fixed__S32_16_create(void) {
Fixed_S32_16 num;
int32_t test_num;
cl_assert(FIXED_S32_16_PRECISION == 16);
test_num = 1 << FIXED_S32_16_PRECISION;
num = (Fixed_S32_16){ .integer = 1, .fraction = 0 };
test_num = (int32_t)((float)1 * (1 << FIXED_S32_16_PRECISION));
cl_assert(num.raw_value == test_num);
cl_assert((FIXED_S32_16_ONE.raw_value == test_num));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S32_16)) == 0);
num = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION)) };
test_num = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S32_16)) == 0);
num = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION)) };
test_num = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S32_16)) == 0);
num = (Fixed_S32_16){ .raw_value = (int32_t)((float)-3.5 * (1 << FIXED_S32_16_PRECISION)) };
test_num = (int32_t)((float)-3.5 * (1 << FIXED_S32_16_PRECISION));
cl_assert(memcmp(&num, &test_num, sizeof(Fixed_S32_16)) == 0);
}
void test_math_fixed__S32_16_add(void) {
Fixed_S32_16 num1, num2;
Fixed_S32_16 sum, sum_c;
// Test number addition
num1 = FIXED_S32_16_ONE;
num2 = FIXED_S32_16_ONE;
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)2 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 3.5 + 1 = 4.5
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION)) };
num2 = FIXED_S32_16_ONE;
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)4.5 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 1 + 3.5 = 4.5 - test commutative property of addition
num1 = FIXED_S32_16_ONE;
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)4.5 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2 + -3 = -5
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-3 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)-5 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2 + 5 = 3
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)5 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)3 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = -2.1 + 5.4 = 3.3
// math is as follows:
// -2.1 * (1 << 16) = -137625.6 = -137625 (drop fraction)
// 5.4 * (1 << 16) = 353894.4 = 353894 (drop fraction)
// -137625 + 353894 = 216269 ~= 3.3
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2.1 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)5.4 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)(216269) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 2.1 - 5.4 = -3.3
// math is as follows:
// 2.1 * (1 << 16) = 137625.6 = 137625 (drop fraction)
// -5.4 * (1 << 16) = -353894.4 = -353894 (drop fraction)
// 137625 - 353894 = -216269 ~= -3.3
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)2.1 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-5.4 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add(num1, num2);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)(-216269) };
cl_assert(sum.raw_value == sum_c.raw_value);
}
void test_math_fixed__S32_16_add3(void) {
Fixed_S32_16 num1, num2, num3;
Fixed_S32_16 sum, sum_c;
// Test number addition
num1 = FIXED_S32_16_ONE;
num2 = FIXED_S32_16_ONE;
num3 = FIXED_S32_16_ONE;
sum = Fixed_S32_16_add3(num1, num2, num3);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)3 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(sum.raw_value == sum_c.raw_value);
// sum = 3.7 + 2.3 + 1.1 = 242483.2 + 150732.8 + 72089.6
// ~= 242483 + 150732 + 72089 = 465304 ~= 7.1
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.7 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)2.3 * (1 << FIXED_S32_16_PRECISION)) };
num3 = (Fixed_S32_16){ .raw_value = (int32_t)((float)1.1 * (1 << FIXED_S32_16_PRECISION)) };
sum = Fixed_S32_16_add3(num1, num2, num3);
sum_c = (Fixed_S32_16){ .raw_value = (int32_t)(465304) };
cl_assert(sum.raw_value == sum_c.raw_value);
}
void test_math_fixed__S32_16_mul(void) {
Fixed_S32_16 num1, num2;
Fixed_S32_16 mul, mul_c;
// Test number muliplication
num1 = FIXED_S32_16_ONE;
num2 = FIXED_S32_16_ONE;
mul = Fixed_S32_16_mul(num1, num2);
mul_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)1 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// 2*3 = 6
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)2 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S32_16_mul(num1, num2);
mul_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)6 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// -2*3 = -6
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S32_16_mul(num1, num2);
mul_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)-6 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// -2*-3 = 6
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-3 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S32_16_mul(num1, num2);
mul_c = (Fixed_S32_16){ .raw_value = (int32_t)((float)6 * (1 << FIXED_S32_16_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// -2.5*-3.3 ==> 163840 * 216268.8 = 163840 * 216268 ==> 35433349120 / 65536 ==> 540670 ~= 8.25
num1 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-2.5 * (1 << FIXED_S32_16_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)-3.3 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S32_16_mul(num1, num2);
mul_c = (Fixed_S32_16){ .raw_value = (int32_t)(540670) };
cl_assert(mul.raw_value == mul_c.raw_value);
}
////////////////////////////////////////////////////////////////
/// Mixed operations
////////////////////////////////////////////////////////////////
void test_math_fixed__S16_3_S32_16_mul(void) {
Fixed_S16_3 num1;
Fixed_S32_16 num2;
Fixed_S16_3 mul, mul_c;
// 1*1 = 1
num1 = FIXED_S16_3_ONE;
num2 = FIXED_S32_16_ONE;
mul = Fixed_S16_3_S32_16_mul(num1, num2);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)1 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// 3.5*1 = 3.5
num1 = (Fixed_S16_3){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
num2 = FIXED_S32_16_ONE;
mul = Fixed_S16_3_S32_16_mul(num1, num2);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// 1*3.5 = 3.5
num1 = FIXED_S16_3_ONE;
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S16_3_S32_16_mul(num1, num2);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// 2.25*3.5 = 7.875
num1 = (Fixed_S16_3){ .raw_value = (int32_t)((float)2.25 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.5 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S16_3_S32_16_mul(num1, num2);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)7.875 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// check surrounding values
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)7.750 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value != mul_c.raw_value);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)8.0 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value != mul_c.raw_value);
// 2.25*3.3 = 7.425
num1 = (Fixed_S16_3){ .raw_value = (int32_t)((float)2.25 * (1 << FIXED_S16_3_PRECISION)) };
num2 = (Fixed_S32_16){ .raw_value = (int32_t)((float)3.3 * (1 << FIXED_S32_16_PRECISION)) };
mul = Fixed_S16_3_S32_16_mul(num1, num2);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)7.425 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
// check surrounding values
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)7.375 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value == mul_c.raw_value);
mul_c = (Fixed_S16_3){ .raw_value = (int32_t)((float)7.5 * (1 << FIXED_S16_3_PRECISION)) };
cl_assert(mul.raw_value != mul_c.raw_value);
}

117
tests/libutil/test_sort.c Normal file
View file

@ -0,0 +1,117 @@
/*
* 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/size.h>
#include <util/sort.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
static int prv_cmp(int32_t a, int32_t b) {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}
static int prv_uint8_cmp(const void *a, const void *b) {
uint8_t t_a = *(uint8_t *)a;
uint8_t t_b = *(uint8_t *)b;
return prv_cmp(t_a, t_b);
}
static int prv_int32_cmp(const void *a, const void *b) {
int32_t t_a = *(int32_t *)a;
int32_t t_b = *(int32_t *)b;
return prv_cmp(t_a, t_b);
}
static int prv_int32_cmp_desc(const void *a, const void *b) {
return -prv_int32_cmp(a, b);
}
void test_sort__uint8_array(void) {
uint8_t array[] = {9, 1, 8, 2, 7, 3, 6, 4, 6, 5, 5};
sort_bubble(array, ARRAY_LENGTH(array), sizeof(uint8_t), prv_uint8_cmp);
uint8_t sorted[] = {1, 2, 3, 4, 5, 5, 6, 6, 7, 8, 9};
cl_assert_equal_m(array, sorted, sizeof(array));
}
void test_sort__int32_array(void) {
int32_t array[] = {-9, 1, 8, 2, 7, 3, -6, 4, 6, 5, 5};
sort_bubble(array, ARRAY_LENGTH(array), sizeof(int32_t), prv_int32_cmp);
int32_t sorted[] = {-9, -6, 1, 2, 3, 4, 5, 5, 6, 7, 8};
cl_assert_equal_m(array, sorted, sizeof(array));
}
void test_sort__int32_array_desc(void) {
int32_t array[] = {-9, 1, 8, 2, 7, 3, -6, 4, 6, 5, 5};
sort_bubble(array, ARRAY_LENGTH(array), sizeof(int32_t), prv_int32_cmp_desc);
int32_t sorted[] = {8, 7, 6, 5, 5, 4, 3, 2, 1, -6, -9};
cl_assert_equal_m(array, sorted, sizeof(array));
}
void test_sort__single_element_array(void) {
int32_t array[] = {1};
sort_bubble(array, ARRAY_LENGTH(array), sizeof(int32_t), prv_int32_cmp);
int32_t sorted[] = {1};
cl_assert_equal_m(array, sorted, sizeof(array));
}
typedef struct MyStruct {
uint8_t nothing;
int32_t number;
uint16_t nothing2;
} MyStruct;
static int prv_MyStruct_cmp(const void *a, const void *b) {
MyStruct *t_a = (MyStruct *)a;
MyStruct *t_b = (MyStruct *)b;
return prv_cmp(t_a->number, t_b->number);
}
void test_sort__sort_structs(void) {
MyStruct array[] = {
{.number = 6 },
{.number = -1 },
{.number = 8 },
{.number = -123 },
};
sort_bubble(array, ARRAY_LENGTH(array), sizeof(MyStruct), prv_MyStruct_cmp);
MyStruct sorted[] = {
{.number = -123 },
{.number = -1 },
{.number = 6 },
{.number = 8 },
};
cl_assert_equal_m(array, sorted, sizeof(array));
}

138
tests/libutil/test_string.c Normal file
View file

@ -0,0 +1,138 @@
/*
* 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/string.h"
#include "clar.h"
#include "stubs_logging.h"
#include "stubs_passert.h"
#include <string.h>
void test_string__initialize(void) {
}
void test_string__cleanup(void) {
}
void test_string__strip_leading_whitespace(void) {
const char *with_whitespace = " hello, world";
const char *without_whitespace = "hello, world";
cl_assert(strcmp(without_whitespace, string_strip_leading_whitespace(with_whitespace)) == 0);
const char *with_newlines = "\n\n\nbonjour, monde";
const char *without_newlines = "bonjour, monde";
cl_assert(strcmp(without_newlines, string_strip_leading_whitespace(with_newlines)) == 0);
const char *with_both = "\n\n \n \nalbuquerque is a lovely town, not!\n";
const char *with_neither = "albuquerque is a lovely town, not!\n";
cl_assert(strcmp(with_neither, string_strip_leading_whitespace(with_both)) == 0);
}
void test_string__strip_trailing_whitespace(void) {
char string_out[100];
const char *with_whitespace = "hello, world ";
const char *without_whitespace = "hello, world";
string_strip_trailing_whitespace(with_whitespace, string_out);
cl_assert(strcmp(without_whitespace, string_out) == 0);
const char *with_newlines = "bonjour, monde\n\n\n";
const char *without_newlines = "bonjour, monde";
string_strip_trailing_whitespace(with_newlines, string_out);
cl_assert(strcmp(without_newlines, string_out) == 0);
const char *with_both = "\n albuquerque is a lovely town, not!\n\n \n \n ";
const char *with_neither = "\n albuquerque is a lovely town, not!";
string_strip_trailing_whitespace(with_both, string_out);
cl_assert(strcmp(with_neither, string_out) == 0);
}
void test_string__test_concat_str_int(void) {
char buf[32];
concat_str_int("app", 1, buf, sizeof(buf));
cl_assert_equal_s(buf, "app1");
concat_str_int("app", 255, buf, sizeof(buf));
cl_assert_equal_s(buf, "app255");
concat_str_int("res_bank", 1, buf, sizeof(buf));
cl_assert_equal_s(buf, "res_bank1");
concat_str_int("res_bank", 255, buf, sizeof(buf));
cl_assert_equal_s(buf, "res_bank255");
}
void test_string__test_itoa_int(void) {
char buf[32];
itoa_int(0, buf, 10);
cl_assert(0 == strcmp(buf, "0"));
itoa_int(-0, buf, 10);
cl_assert(0 == strcmp(buf, "0"));
itoa_int(1, buf, 10);
cl_assert(0 == strcmp(buf, "1"));
itoa_int(-1, buf, 10);
cl_assert(0 == strcmp(buf, "-1"));
itoa_int(365, buf, 10);
cl_assert(0 == strcmp(buf, "365"));
itoa_int(-365, buf, 10);
cl_assert(0 == strcmp(buf, "-365"));
// max int32
itoa_int(2147483647, buf, 10);
cl_assert(0 == strcmp(buf, "2147483647"));
// min int32
itoa_int(-2147483647, buf, 10);
cl_assert(0 == strcmp(buf, "-2147483647"));
}
void test_string__test_byte_stream_to_hex_string(void) {
char result_buf[256]; // arbitraily large
const uint8_t byte_stream[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
const char *expected_result_fwd = "00010203040506070809";
const char *expected_result_bkwd = "09080706050403020100";
// check that fwd decoding byte streams work
byte_stream_to_hex_string(&result_buf[0], sizeof(result_buf),
byte_stream, sizeof(byte_stream), false);
int res = strcmp(&result_buf[0], expected_result_fwd);
cl_assert(res == 0);
// check that bkwd decoding bytes streams work
byte_stream_to_hex_string(&result_buf[0], sizeof(result_buf),
byte_stream, sizeof(byte_stream), true);
res = strcmp(&result_buf[0], expected_result_bkwd);
cl_assert(res == 0);
// check that we truncate correctly if result buffer is too small
// in this case lets make it so there is not enough space for the '\0' byte
size_t truncated_size = sizeof(byte_stream) * 2;
memset(result_buf, 0x00, sizeof(result_buf)); // reset buffer
byte_stream_to_hex_string(&result_buf[0], truncated_size, byte_stream,
sizeof(byte_stream), false);
res = memcmp(&result_buf[0], expected_result_fwd, strlen(expected_result_fwd) - 2);
cl_assert(res == 0 && result_buf[truncated_size - 1] == '\0');
}

View file

@ -0,0 +1,45 @@
/*
* 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/struct.h"
typedef struct NullSafeFieldAccessTestStruct {
int field_to_access;
int *ptr_field_to_access;
} NullSafeFieldAccessTestStruct;
void test_struct__null_safe_access_field(void) {
// Passing in NULL for the struct ptr should return the default value
// (supporting both pointer and non-pointer types)
NullSafeFieldAccessTestStruct *null_ptr = NULL;
cl_assert_equal_i(NULL_SAFE_FIELD_ACCESS(null_ptr, field_to_access, 1234), 1234);
cl_assert_equal_p(NULL_SAFE_FIELD_ACCESS(null_ptr, ptr_field_to_access, NULL), NULL);
int data = 1337;
const NullSafeFieldAccessTestStruct test_struct = (NullSafeFieldAccessTestStruct) {
.field_to_access = data,
.ptr_field_to_access = &data,
};
// Passing in a valid struct ptr should return the field
// (supporting both pointer and non-pointer types)
const int result = NULL_SAFE_FIELD_ACCESS(&test_struct, field_to_access, 1234);
cl_assert_equal_i(result, test_struct.field_to_access);
const int *ptr_result = NULL_SAFE_FIELD_ACCESS(&test_struct, ptr_field_to_access, NULL);
cl_assert_equal_p(ptr_result, test_struct.ptr_field_to_access);
}

86
tests/libutil/test_uuid.c Normal file
View file

@ -0,0 +1,86 @@
/*
* 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/uuid.h"
#include "fake_rtc.h"
#include "stubs_passert.h"
#include "stubs_rand_ptr.h"
#include "stubs_pebble_tasks.h"
void test_uuid__equal(void) {
const Uuid system = UUID_SYSTEM;
const Uuid invalid = UUID_INVALID;
cl_assert(uuid_equal(&system, &system));
cl_assert(uuid_equal(&invalid, &invalid));
cl_assert(!uuid_equal(&system, &invalid));
const Uuid test_uuid_1 = (Uuid) {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5
};
// Different at the start
Uuid test_uuid_2 = test_uuid_1;
++test_uuid_2.byte0;
// Different at the end
Uuid test_uuid_3 = test_uuid_1;
++test_uuid_3.byte15;
cl_assert(uuid_equal(&test_uuid_1, &test_uuid_1));
cl_assert(uuid_equal(&test_uuid_2, &test_uuid_2));
cl_assert(uuid_equal(&test_uuid_3, &test_uuid_3));
cl_assert(!uuid_equal(&test_uuid_1, &test_uuid_2));
cl_assert(!uuid_equal(&test_uuid_1, &test_uuid_3));
}
void test_uuid__invalid(void) {
const Uuid system = UUID_SYSTEM;
const Uuid invalid = UUID_INVALID;
const Uuid test_uuid_1 = (Uuid) {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5
};
cl_assert(uuid_is_invalid(&invalid));
cl_assert(!uuid_is_invalid(&system));
cl_assert(!uuid_is_invalid(&test_uuid_1));
}
void test_uuid__string(void) {
char buffer[UUID_STRING_BUFFER_LENGTH];
const Uuid test_uuid_1 = (Uuid) {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5
};
uuid_to_string(&test_uuid_1, buffer);
cl_assert_equal_s(buffer, "{00010203-0405-0607-0809-000102030405}");
const Uuid system = UUID_SYSTEM;
uuid_to_string(&system, buffer);
cl_assert_equal_s(buffer, "{00000000-0000-0000-0000-000000000000}");
const Uuid invalid = UUID_INVALID;
uuid_to_string(&invalid, buffer);
cl_assert_equal_s(buffer, "{ffffffff-ffff-ffff-ffff-ffffffffffff}");
uuid_to_string(NULL, buffer);
cl_assert_equal_s(buffer, "{NULL UUID}");
}

50
tests/libutil/wscript Normal file
View file

@ -0,0 +1,50 @@
from waftools.pebble_test import clar
def build(ctx):
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob="test_circular_buffer.c")
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob="test_list.c")
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob="test_math.c",
test_libs=['m'])
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob="test_string.c")
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob="test_math_fixed.c")
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_crc32.c')
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_uuid.c')
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_circular_cache.c')
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_keyed_circular_cache.c')
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_struct.c')
clar(ctx,
sources_ant_glob=None,
test_sources_ant_glob='test_sort.c')
# vim:filetype=python