[FL-3062] Fix unit tests (#2180)

* SubGHZ unit test: fail if async_tx is not started
* Memgr unit test: fix for multithreaded enviroment
* Unit tests: fix failed_tests count
* Unit tests: remove debug code
* Double update test: increase flipper detection time

Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
Sergey Gavrilov 2022-12-25 00:13:21 +10:00 committed by GitHub
parent b0970953b9
commit c2cb14834d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 44 additions and 100 deletions

View File

@ -3,98 +3,37 @@
#include <string.h> #include <string.h>
#include <stdbool.h> #include <stdbool.h>
// this test is not accurate, but gives a basic understanding
// that memory management is working fine
// do not include memmgr.h here
// we also test that we are linking against stdlib
extern size_t memmgr_get_free_heap(void);
extern size_t memmgr_get_minimum_free_heap(void);
// current heap management realization consume:
// X bytes after allocate and 0 bytes after allocate and free,
// where X = sizeof(void*) + sizeof(size_t), look to BlockLink_t
const size_t heap_overhead_max_size = sizeof(void*) + sizeof(size_t);
bool heap_equal(size_t heap_size, size_t heap_size_old) {
// heap borders with overhead
const size_t heap_low = heap_size_old - heap_overhead_max_size;
const size_t heap_high = heap_size_old + heap_overhead_max_size;
// not exact, so we must test it against bigger numbers than "overhead size"
const bool result = ((heap_size >= heap_low) && (heap_size <= heap_high));
// debug allocation info
if(!result) {
printf("\n(hl: %zu) <= (p: %zu) <= (hh: %zu)\n", heap_low, heap_size, heap_high);
}
return result;
}
void test_furi_memmgr() { void test_furi_memmgr() {
size_t heap_size = 0; void* ptr;
size_t heap_size_old = 0;
const int alloc_size = 128;
void* ptr = NULL;
void* original_ptr = NULL;
// do not include furi memmgr.h case
#ifdef FURI_MEMMGR_GUARD
mu_fail("do not link against furi memmgr.h");
#endif
// allocate memory case // allocate memory case
heap_size_old = memmgr_get_free_heap(); ptr = malloc(100);
ptr = malloc(alloc_size); mu_check(ptr != NULL);
heap_size = memmgr_get_free_heap(); // test that memory is zero-initialized after allocation
mu_assert_pointers_not_eq(ptr, NULL); for(int i = 0; i < 100; i++) {
mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "allocate failed"); mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
}
// free memory case
heap_size_old = memmgr_get_free_heap();
free(ptr); free(ptr);
ptr = NULL;
heap_size = memmgr_get_free_heap();
mu_assert(heap_equal(heap_size, heap_size_old + alloc_size), "free failed");
// reallocate memory case // reallocate memory case
ptr = malloc(100);
memset(ptr, 66, 100);
ptr = realloc(ptr, 200);
mu_check(ptr != NULL);
// get filled array with some data // test that memory is really reallocated
original_ptr = malloc(alloc_size); for(int i = 0; i < 100; i++) {
mu_assert_pointers_not_eq(original_ptr, NULL); mu_assert_int_eq(66, ((uint8_t*)ptr)[i]);
for(int i = 0; i < alloc_size; i++) {
*(unsigned char*)(original_ptr + i) = i;
} }
// malloc array and copy data // TODO: fix realloc to copy only old size, and write testcase that leftover of reallocated memory is zero-initialized
ptr = malloc(alloc_size);
mu_assert_pointers_not_eq(ptr, NULL);
memcpy(ptr, original_ptr, alloc_size);
// reallocate array
heap_size_old = memmgr_get_free_heap();
ptr = realloc(ptr, alloc_size * 2);
heap_size = memmgr_get_free_heap();
mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "reallocate failed");
mu_assert_int_eq(memcmp(original_ptr, ptr, alloc_size), 0);
free(original_ptr);
free(ptr); free(ptr);
// allocate and zero-initialize array (calloc) // allocate and zero-initialize array (calloc)
original_ptr = malloc(alloc_size); ptr = calloc(100, 2);
mu_assert_pointers_not_eq(original_ptr, NULL); mu_check(ptr != NULL);
for(int i = 0; i < 100 * 2; i++) {
for(int i = 0; i < alloc_size; i++) { mu_assert_int_eq(0, ((uint8_t*)ptr)[i]);
*(unsigned char*)(original_ptr + i) = 0;
} }
heap_size_old = memmgr_get_free_heap();
ptr = calloc(1, alloc_size);
heap_size = memmgr_get_free_heap();
mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "callocate failed");
mu_assert_int_eq(memcmp(original_ptr, ptr, alloc_size), 0);
free(original_ptr);
free(ptr); free(ptr);
} }

View File

@ -318,7 +318,10 @@ bool subghz_hal_async_tx_test_run(SubGhzHalAsyncTxTestType type) {
furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async); furi_hal_subghz_load_preset(FuriHalSubGhzPresetOok650Async);
furi_hal_subghz_set_frequency_and_path(433920000); furi_hal_subghz_set_frequency_and_path(433920000);
furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test); if(!furi_hal_subghz_start_async_tx(subghz_hal_async_tx_test_yield, &test)) {
return false;
}
while(!furi_hal_subghz_is_async_tx_complete()) { while(!furi_hal_subghz_is_async_tx_complete()) {
furi_delay_ms(10); furi_delay_ms(10);
} }

View File

@ -73,7 +73,6 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
UNUSED(cli); UNUSED(cli);
UNUSED(args); UNUSED(args);
UNUSED(context); UNUSED(context);
uint32_t failed_tests = 0;
minunit_run = 0; minunit_run = 0;
minunit_assert = 0; minunit_assert = 0;
minunit_fail = 0; minunit_fail = 0;
@ -99,32 +98,35 @@ void unit_tests_cli(Cli* cli, FuriString* args, void* context) {
if(furi_string_size(args)) { if(furi_string_size(args)) {
if(furi_string_cmp_str(args, unit_tests[i].name) == 0) { if(furi_string_cmp_str(args, unit_tests[i].name) == 0) {
failed_tests += unit_tests[i].entry(); unit_tests[i].entry();
} else { } else {
printf("Skipping %s\r\n", unit_tests[i].name); printf("Skipping %s\r\n", unit_tests[i].name);
} }
} else { } else {
failed_tests += unit_tests[i].entry(); unit_tests[i].entry();
} }
} }
printf("\r\nFailed tests: %lu\r\n", failed_tests);
// Time report if(minunit_run != 0) {
cycle_counter = (furi_get_tick() - cycle_counter); printf("\r\nFailed tests: %u\r\n", minunit_fail);
printf("Consumed: %lu ms\r\n", cycle_counter);
// Wait for tested services and apps to deallocate memory // Time report
furi_delay_ms(200); cycle_counter = (furi_get_tick() - cycle_counter);
uint32_t heap_after = memmgr_get_free_heap(); printf("Consumed: %lu ms\r\n", cycle_counter);
printf("Leaked: %ld\r\n", heap_before - heap_after);
// Final Report // Wait for tested services and apps to deallocate memory
if(failed_tests == 0) { furi_delay_ms(200);
notification_message(notification, &sequence_success); uint32_t heap_after = memmgr_get_free_heap();
printf("Status: PASSED\r\n"); printf("Leaked: %ld\r\n", heap_before - heap_after);
} else {
notification_message(notification, &sequence_error); // Final Report
printf("Status: FAILED\r\n"); if(minunit_fail == 0) {
notification_message(notification, &sequence_success);
printf("Status: PASSED\r\n");
} else {
notification_message(notification, &sequence_error);
printf("Status: FAILED\r\n");
}
} }
} }

View File

@ -24,7 +24,7 @@ def flp_serial_by_name(flp_name):
return "" return ""
UPDATE_TIMEOUT = 60 UPDATE_TIMEOUT = 60 * 4 # 4 minutes
def main(): def main():