merge from master, menu not work

This commit is contained in:
aanper
2020-10-16 07:42:08 +03:00
19 changed files with 802 additions and 270 deletions

View File

@@ -26,6 +26,8 @@ C_SOURCES += $(APP_DIR)/tests/furi_record_test.c
C_SOURCES += $(APP_DIR)/tests/test_index.c
C_SOURCES += $(APP_DIR)/tests/minunit_test.c
C_SOURCES += $(APP_DIR)/tests/furi_valuemutex_test.c
C_SOURCES += $(APP_DIR)/tests/furi_pubsub_test.c
C_SOURCES += $(APP_DIR)/tests/furi_memmgr_test.c
endif
APP_EXAMPLE_BLINK ?= 0

View File

@@ -0,0 +1,99 @@
#include "minunit.h"
#include <stdlib.h>
#include <string.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 managment 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 extact, 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() {
size_t heap_size = 0;
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
heap_size_old = memmgr_get_free_heap();
ptr = malloc(alloc_size);
heap_size = memmgr_get_free_heap();
mu_assert_pointers_not_eq(ptr, NULL);
mu_assert(heap_equal(heap_size, heap_size_old - alloc_size), "allocate failed");
// free memory case
heap_size_old = memmgr_get_free_heap();
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
// get filled array with some data
original_ptr = malloc(alloc_size);
mu_assert_pointers_not_eq(original_ptr, NULL);
for(int i = 0; i < alloc_size; i++) {
*(unsigned char*)(original_ptr + i) = i;
}
// malloc array and copy data
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);
// allocate and zero-initialize array (calloc)
original_ptr = malloc(alloc_size);
mu_assert_pointers_not_eq(original_ptr, NULL);
for(int i = 0; i < alloc_size; 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);
}

View File

@@ -0,0 +1,56 @@
#include <stdio.h>
#include <string.h>
#include "flipper_v2.h"
#include "log.h"
#include "minunit.h"
const uint32_t context_value = 0xdeadbeef;
const uint32_t notify_value_0 = 0x12345678;
const uint32_t notify_value_1 = 0x11223344;
uint32_t pubsub_value = 0;
uint32_t pubsub_context_value = 0;
void test_pubsub_handler(void* arg, void* ctx) {
pubsub_value = *(uint32_t*)arg;
pubsub_context_value = *(uint32_t*)ctx;
}
void test_furi_pubsub() {
bool result;
PubSub test_pubsub;
PubSubItem* test_pubsub_item;
// init pubsub case
result = init_pubsub(&test_pubsub);
mu_assert(result, "init pubsub failed");
// subscribe pubsub case
test_pubsub_item = subscribe_pubsub(&test_pubsub, test_pubsub_handler, (void*)&context_value);
mu_assert_pointers_not_eq(test_pubsub_item, NULL);
/// notify pubsub case
result = notify_pubsub(&test_pubsub, (void*)&notify_value_0);
mu_assert(result, "notify pubsub failed");
mu_assert_int_eq(pubsub_value, notify_value_0);
mu_assert_int_eq(pubsub_context_value, context_value);
// unsubscribe pubsub case
result = unsubscribe_pubsub(test_pubsub_item);
mu_assert(result, "unsubscribe pubsub failed");
result = unsubscribe_pubsub(test_pubsub_item);
mu_assert(!result, "unsubscribe pubsub not failed");
/// notify unsubscribed pubsub case
result = notify_pubsub(&test_pubsub, (void*)&notify_value_1);
mu_assert(result, "notify pubsub failed");
mu_assert_int_not_eq(pubsub_value, notify_value_1);
// delete pubsub case
result = delete_pubsub(&test_pubsub);
mu_assert(result, "unsubscribe pubsub failed");
// TODO test case that the pubsub_delete will remove pubsub from heap
}

View File

@@ -14,197 +14,3 @@ void test_furi_create_open() {
void* record = furi_open("test/holding");
mu_assert_pointers_eq(record, &test_data);
}
/*
TEST: non-existent data
1. Try to open non-existent record
2. Check for NULL handler
3. Try to write/read, get error
TODO: implement this test
*/
bool test_furi_nonexistent_data() {
return true;
}
/*
TEST: mute algorithm
1. Create "parent" application:
1. Create pipe record
2. Open watch handler: no_mute=false, solo=false, subscribe to data.
2. Open handler A: no_mute=false, solo=false, NULL subscriber. Subscribe to state.
Try to write data to A and check subscriber.
3. Open handler B: no_mute=true, solo=true, NULL subscriber.
Check A state cb get FlipperRecordStateMute.
Try to write data to A and check that subscriber get no data. (muted)
Try to write data to B and check that subscriber get data.
TODO: test 3 not pass beacuse state callback not implemented
4. Open hadler C: no_mute=false, solo=true, NULL subscriber.
Try to write data to A and check that subscriber get no data. (muted)
Try to write data to B and check that subscriber get data. (not muted because open with no_mute)
Try to write data to C and check that subscriber get data.
5. Open handler D: no_mute=false, solo=false, NULL subscriber.
Try to write data to A and check that subscriber get no data. (muted)
Try to write data to B and check that subscriber get data. (not muted because open with no_mute)
Try to write data to C and check that subscriber get data. (not muted because D open without solo)
Try to write data to D and check that subscriber get data.
6. Close C, close B.
Check A state cb get FlipperRecordStateUnmute
Try to write data to A and check that subscriber get data. (unmuted)
Try to write data to D and check that subscriber get data.
TODO: test 6 not pass beacuse cleanup is not implemented
TODO: test 6 not pass because mute algorithm is unfinished.
7. Exit "parent application"
Check A state cb get FlipperRecordStateDeleted
TODO: test 7 not pass beacuse cleanup is not implemented
*/
static uint8_t mute_last_value = 0;
static FlipperRecordState mute_last_state = 255;
void mute_record_cb(const void* value, size_t size, void* ctx) {
// hold value to static var
mute_last_value = *((uint8_t*)value);
}
void mute_record_state_cb(FlipperRecordState state, void* ctx) {
mute_last_state = state;
}
void furi_mute_parent_app(void* p) {
// 1. Create pipe record
if(!furi_create_deprecated("test/mute", NULL, 0)) {
printf("cannot create record\n");
furiac_exit(NULL);
}
// 2. Open watch handler: solo=false, no_mute=false, subscribe to data
FuriRecordSubscriber* watch_handler =
furi_open_deprecated("test/mute", false, false, mute_record_cb, NULL, NULL);
if(watch_handler == NULL) {
printf("cannot open watch handler\n");
furiac_exit(NULL);
}
while(1) {
// TODO we don't have thread sleep
delay(100000);
}
}
bool test_furi_mute_algorithm() {
// 1. Create "parent" application:
FuriApp* parent_app = furiac_start(furi_mute_parent_app, "parent app", NULL);
delay(2); // wait creating record
// 2. Open handler A: solo=false, no_mute=false, NULL subscriber. Subscribe to state.
FuriRecordSubscriber* handler_a =
furi_open_deprecated("test/mute", false, false, NULL, mute_record_state_cb, NULL);
if(handler_a == NULL) {
printf("cannot open handler A\n");
return false;
}
uint8_t test_counter = 1;
// Try to write data to A and check subscriber
if(!furi_write(handler_a, &test_counter, sizeof(uint8_t))) {
printf("write to A failed\n");
return false;
}
if(mute_last_value != test_counter) {
printf("value A mismatch: %d vs %d\n", mute_last_value, test_counter);
return false;
}
// 3. Open handler B: solo=true, no_mute=true, NULL subscriber.
FuriRecordSubscriber* handler_b =
furi_open_deprecated("test/mute", true, true, NULL, NULL, NULL);
if(handler_b == NULL) {
printf("cannot open handler B\n");
return false;
}
// Check A state cb get FlipperRecordStateMute.
if(mute_last_state != FlipperRecordStateMute) {
printf("A state is not FlipperRecordStateMute: %d\n", mute_last_state);
return false;
}
test_counter = 2;
// Try to write data to A and check that subscriber get no data. (muted)
if(furi_write(handler_a, &test_counter, sizeof(uint8_t))) {
printf("A not muted\n");
return false;
}
if(mute_last_value == test_counter) {
printf("value A must be muted\n");
return false;
}
test_counter = 3;
// Try to write data to B and check that subscriber get data.
if(!furi_write(handler_b, &test_counter, sizeof(uint8_t))) {
printf("write to B failed\n");
return false;
}
if(mute_last_value != test_counter) {
printf("value B mismatch: %d vs %d\n", mute_last_value, test_counter);
return false;
}
// 4. Open hadler C: solo=true, no_mute=false, NULL subscriber.
FuriRecordSubscriber* handler_c =
furi_open_deprecated("test/mute", true, false, NULL, NULL, NULL);
if(handler_c == NULL) {
printf("cannot open handler C\n");
return false;
}
// TODO: Try to write data to A and check that subscriber get no data. (muted)
// TODO: Try to write data to B and check that subscriber get data. (not muted because open with no_mute)
// TODO: Try to write data to C and check that subscriber get data.
// 5. Open handler D: solo=false, no_mute=false, NULL subscriber.
FuriRecordSubscriber* handler_d =
furi_open_deprecated("test/mute", false, false, NULL, NULL, NULL);
if(handler_d == NULL) {
printf("cannot open handler D\n");
return false;
}
// TODO: Try to write data to A and check that subscriber get no data. (muted)
// TODO: Try to write data to B and check that subscriber get data. (not muted because open with no_mute)
// TODO: Try to write data to C and check that subscriber get data. (not muted because D open without solo)
// TODO: Try to write data to D and check that subscriber get data.
// 6. Close C, close B.
// TODO: Check A state cb get FlipperRecordStateUnmute
// TODO: Try to write data to A and check that subscriber get data. (unmuted)
// TODO: Try to write data to D and check that subscriber get data.
// 7. Exit "parent application"
if(!furiac_kill(parent_app)) {
printf("kill parent_app fail\n");
return false;
}
// TODO: Check A state cb get FlipperRecordStateDeleted
return true;
}

View File

@@ -7,13 +7,13 @@
bool test_furi_ac_create_kill();
bool test_furi_ac_switch_exit();
bool test_furi_nonexistent_data();
bool test_furi_mute_algorithm();
// v2 tests
void test_furi_create_open();
void test_furi_valuemutex();
void test_furi_concurrent_access();
void test_furi_pubsub();
void test_furi_memmgr();
static int foo = 0;
@@ -37,10 +37,6 @@ MU_TEST(mu_test_furi_ac_switch_exit) {
mu_assert_int_eq(test_furi_ac_switch_exit(), true);
}
MU_TEST(mu_test_furi_nonexistent_data) {
mu_assert_int_eq(test_furi_nonexistent_data(), true);
}
// v2 tests
MU_TEST(mu_test_furi_create_open) {
test_furi_create_open();
@@ -54,6 +50,16 @@ MU_TEST(mu_test_furi_concurrent_access) {
test_furi_concurrent_access();
}
MU_TEST(mu_test_furi_pubsub) {
test_furi_pubsub();
}
MU_TEST(mu_test_furi_memmgr) {
// this test is not accurate, but gives a basic understanding
// that memory management is working fine
test_furi_memmgr();
}
MU_TEST_SUITE(test_suite) {
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
@@ -61,12 +67,13 @@ MU_TEST_SUITE(test_suite) {
MU_RUN_TEST(mu_test_furi_ac_create_kill);
MU_RUN_TEST(mu_test_furi_ac_switch_exit);
MU_RUN_TEST(mu_test_furi_nonexistent_data);
// v2 tests
MU_RUN_TEST(mu_test_furi_create_open);
MU_RUN_TEST(mu_test_furi_valuemutex);
MU_RUN_TEST(mu_test_furi_concurrent_access);
MU_RUN_TEST(mu_test_furi_pubsub);
MU_RUN_TEST(mu_test_furi_memmgr);
}
int run_minunit() {