Skip to content

Commit 8350227

Browse files
Merge branch 'dev' into portasynthinca3/3348-softspi
2 parents 752b708 + 913a86b commit 8350227

File tree

14 files changed

+209
-100
lines changed

14 files changed

+209
-100
lines changed
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
#include <furi.h>
2+
#include <errno.h>
3+
#include "../test.h" // IWYU pragma: keep
4+
5+
#define TAG "ErrnoTest"
6+
#define THREAD_CNT 16
7+
#define ITER_CNT 1000
8+
9+
static int32_t errno_fuzzer(void* context) {
10+
int start_value = (int)context;
11+
int32_t fails = 0;
12+
13+
for(int i = start_value; i < start_value + ITER_CNT; i++) {
14+
errno = i;
15+
furi_thread_yield();
16+
if(errno != i) fails++;
17+
}
18+
19+
for(int i = 0; i < ITER_CNT; i++) {
20+
errno = 0;
21+
furi_thread_yield();
22+
UNUSED(strtol("123456", NULL, 10)); // -V530
23+
furi_thread_yield();
24+
if(errno != 0) fails++;
25+
26+
errno = 0;
27+
furi_thread_yield();
28+
UNUSED(strtol("123456123456123456123456123456123456123456123456", NULL, 10)); // -V530
29+
furi_thread_yield();
30+
if(errno != ERANGE) fails++;
31+
}
32+
33+
return fails;
34+
}
35+
36+
void test_errno_saving(void) {
37+
FuriThread* threads[THREAD_CNT];
38+
39+
for(int i = 0; i < THREAD_CNT; i++) {
40+
int start_value = i * ITER_CNT;
41+
threads[i] = furi_thread_alloc_ex("ErrnoFuzzer", 1024, errno_fuzzer, (void*)start_value);
42+
furi_thread_set_priority(threads[i], FuriThreadPriorityNormal);
43+
furi_thread_start(threads[i]);
44+
}
45+
46+
for(int i = 0; i < THREAD_CNT; i++) {
47+
furi_thread_join(threads[i]);
48+
mu_assert_int_eq(0, furi_thread_get_return_code(threads[i]));
49+
furi_thread_free(threads[i]);
50+
}
51+
}

applications/debug/unit_tests/tests/furi/furi_test.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ void test_furi_concurrent_access(void);
88
void test_furi_pubsub(void);
99
void test_furi_memmgr(void);
1010
void test_furi_event_loop(void);
11+
void test_errno_saving(void);
1112

1213
static int foo = 0;
1314

@@ -42,6 +43,10 @@ MU_TEST(mu_test_furi_event_loop) {
4243
test_furi_event_loop();
4344
}
4445

46+
MU_TEST(mu_test_errno_saving) {
47+
test_errno_saving();
48+
}
49+
4550
MU_TEST_SUITE(test_suite) {
4651
MU_SUITE_CONFIGURE(&test_setup, &test_teardown);
4752
MU_RUN_TEST(test_check);
@@ -51,6 +56,7 @@ MU_TEST_SUITE(test_suite) {
5156
MU_RUN_TEST(mu_test_furi_pubsub);
5257
MU_RUN_TEST(mu_test_furi_memmgr);
5358
MU_RUN_TEST(mu_test_furi_event_loop);
59+
MU_RUN_TEST(mu_test_errno_saving);
5460
}
5561

5662
int run_minunit_test_furi(void) {

applications/debug/unit_tests/tests/storage/storage_test.c

Lines changed: 68 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66
// This is a hack to access internal storage functions and definitions
77
#include <storage/storage_i.h>
88

9-
#define UNIT_TESTS_PATH(path) EXT_PATH("unit_tests/" path)
9+
#define UNIT_TESTS_RESOURCES_PATH(path) EXT_PATH("unit_tests/" path)
10+
#define UNIT_TESTS_PATH(path) EXT_PATH(".tmp/unit_tests/" path)
1011

11-
#define STORAGE_LOCKED_FILE EXT_PATH("locked_file.test")
12+
#define STORAGE_LOCKED_FILE UNIT_TESTS_PATH("locked_file.test")
1213
#define STORAGE_LOCKED_DIR STORAGE_INT_PATH_PREFIX
1314

1415
#define STORAGE_TEST_DIR UNIT_TESTS_PATH("test_dir")
@@ -369,44 +370,92 @@ MU_TEST(storage_file_rename) {
369370
Storage* storage = furi_record_open(RECORD_STORAGE);
370371
File* file = storage_file_alloc(storage);
371372

372-
mu_check(write_file_13DA(storage, EXT_PATH("file.old")));
373-
mu_check(check_file_13DA(storage, EXT_PATH("file.old")));
373+
mu_check(write_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
374+
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.old")));
374375
mu_assert_int_eq(
375-
FSE_OK, storage_common_rename(storage, EXT_PATH("file.old"), EXT_PATH("file.new")));
376-
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("file.old"), NULL));
377-
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, EXT_PATH("file.new"), NULL));
378-
mu_check(check_file_13DA(storage, EXT_PATH("file.new")));
379-
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, EXT_PATH("file.new")));
376+
FSE_OK,
377+
storage_common_rename(storage, UNIT_TESTS_PATH("file.old"), UNIT_TESTS_PATH("file.new")));
378+
mu_assert_int_eq(
379+
FSE_NOT_EXIST, storage_common_stat(storage, UNIT_TESTS_PATH("file.old"), NULL));
380+
mu_assert_int_eq(FSE_OK, storage_common_stat(storage, UNIT_TESTS_PATH("file.new"), NULL));
381+
mu_check(check_file_13DA(storage, UNIT_TESTS_PATH("file.new")));
382+
mu_assert_int_eq(FSE_OK, storage_common_remove(storage, UNIT_TESTS_PATH("file.new")));
380383

381384
storage_file_free(file);
382385
furi_record_close(RECORD_STORAGE);
383386
}
384387

388+
static const char* dir_rename_tests[][2] = {
389+
{UNIT_TESTS_PATH("dir.old"), UNIT_TESTS_PATH("dir.new")},
390+
{UNIT_TESTS_PATH("test_dir"), UNIT_TESTS_PATH("test_dir-new")},
391+
{UNIT_TESTS_PATH("test"), UNIT_TESTS_PATH("test-test")},
392+
};
393+
385394
MU_TEST(storage_dir_rename) {
386395
Storage* storage = furi_record_open(RECORD_STORAGE);
387396

388-
storage_dir_create(storage, EXT_PATH("dir.old"));
397+
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
398+
const char* old_path = dir_rename_tests[i][0];
399+
const char* new_path = dir_rename_tests[i][1];
400+
401+
storage_dir_create(storage, old_path);
402+
mu_check(storage_dir_rename_check(storage, old_path));
403+
404+
mu_assert_int_eq(FSE_OK, storage_common_rename(storage, old_path, new_path));
405+
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, old_path, NULL));
406+
mu_check(storage_dir_rename_check(storage, new_path));
407+
408+
storage_dir_remove(storage, new_path);
409+
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, new_path, NULL));
410+
}
411+
412+
furi_record_close(RECORD_STORAGE);
413+
}
389414

390-
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.old")));
415+
MU_TEST(storage_equiv_and_subdir) {
416+
Storage* storage = furi_record_open(RECORD_STORAGE);
391417

392418
mu_assert_int_eq(
393-
FSE_OK, storage_common_rename(storage, EXT_PATH("dir.old"), EXT_PATH("dir.new")));
394-
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.old"), NULL));
395-
mu_check(storage_dir_rename_check(storage, EXT_PATH("dir.new")));
419+
true,
420+
storage_common_equivalent_path(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
421+
mu_assert_int_eq(
422+
true,
423+
storage_common_equivalent_path(
424+
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah/")));
425+
mu_assert_int_eq(
426+
false,
427+
storage_common_equivalent_path(
428+
storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
429+
mu_assert_int_eq(
430+
false,
431+
storage_common_equivalent_path(
432+
storage, UNIT_TESTS_PATH("blah/"), UNIT_TESTS_PATH("blah-blah/")));
396433

397-
storage_dir_remove(storage, EXT_PATH("dir.new"));
398-
mu_assert_int_eq(FSE_NOT_EXIST, storage_common_stat(storage, EXT_PATH("dir.new"), NULL));
434+
mu_assert_int_eq(
435+
true, storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah")));
436+
mu_assert_int_eq(
437+
true,
438+
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah/blah")));
439+
mu_assert_int_eq(
440+
false,
441+
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah/blah"), UNIT_TESTS_PATH("blah")));
442+
mu_assert_int_eq(
443+
false,
444+
storage_common_is_subdir(storage, UNIT_TESTS_PATH("blah"), UNIT_TESTS_PATH("blah-blah")));
399445

400446
furi_record_close(RECORD_STORAGE);
401447
}
402448

403449
MU_TEST_SUITE(storage_rename) {
404450
MU_RUN_TEST(storage_file_rename);
405451
MU_RUN_TEST(storage_dir_rename);
452+
MU_RUN_TEST(storage_equiv_and_subdir);
406453

407454
Storage* storage = furi_record_open(RECORD_STORAGE);
408-
storage_dir_remove(storage, EXT_PATH("dir.old"));
409-
storage_dir_remove(storage, EXT_PATH("dir.new"));
455+
for(size_t i = 0; i < COUNT_OF(dir_rename_tests); i++) {
456+
storage_dir_remove(storage, dir_rename_tests[i][0]);
457+
storage_dir_remove(storage, dir_rename_tests[i][1]);
458+
}
410459
furi_record_close(RECORD_STORAGE);
411460
}
412461

@@ -653,7 +702,7 @@ MU_TEST(test_md5_calc) {
653702
Storage* storage = furi_record_open(RECORD_STORAGE);
654703
File* file = storage_file_alloc(storage);
655704

656-
const char* path = UNIT_TESTS_PATH("storage/md5.txt");
705+
const char* path = UNIT_TESTS_RESOURCES_PATH("storage/md5.txt");
657706
const char* md5_cstr = "2a456fa43e75088fdde41c93159d62a2";
658707
const uint8_t md5[MD5_HASH_SIZE] = {
659708
0x2a,

applications/main/gpio/scenes/gpio_scene_config.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,3 @@ ADD_SCENE(gpio, test, Test)
33
ADD_SCENE(gpio, usb_uart, UsbUart)
44
ADD_SCENE(gpio, usb_uart_cfg, UsbUartCfg)
55
ADD_SCENE(gpio, usb_uart_close_rpc, UsbUartCloseRpc)
6-
ADD_SCENE(gpio, exit_confirm, ExitConfirm)

applications/main/gpio/scenes/gpio_scene_exit_confirm.c

Lines changed: 0 additions & 44 deletions
This file was deleted.

applications/main/gpio/scenes/gpio_scene_usb_uart.c

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,29 @@ typedef struct {
66
UsbUartState state;
77
} SceneUsbUartBridge;
88

9-
static SceneUsbUartBridge* scene_usb_uart;
9+
static SceneUsbUartBridge* scene_usb_uart = NULL;
1010

1111
void gpio_scene_usb_uart_callback(GpioCustomEvent event, void* context) {
1212
furi_assert(context);
1313
GpioApp* app = context;
1414
view_dispatcher_send_custom_event(app->view_dispatcher, event);
1515
}
1616

17+
void gpio_scene_usb_uart_dialog_callback(DialogExResult result, void* context) {
18+
GpioApp* app = context;
19+
if(result == DialogExResultLeft) {
20+
usb_uart_disable(app->usb_uart_bridge);
21+
free(scene_usb_uart);
22+
scene_usb_uart = NULL;
23+
scene_manager_search_and_switch_to_previous_scene(app->scene_manager, GpioSceneStart);
24+
} else {
25+
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
26+
}
27+
}
28+
1729
void gpio_scene_usb_uart_on_enter(void* context) {
1830
GpioApp* app = context;
19-
uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, GpioAppViewUsbUart);
20-
if(prev_state == 0) {
31+
if(!scene_usb_uart) {
2132
scene_usb_uart = malloc(sizeof(SceneUsbUartBridge));
2233
scene_usb_uart->cfg.vcp_ch = 0;
2334
scene_usb_uart->cfg.uart_ch = 0;
@@ -31,19 +42,23 @@ void gpio_scene_usb_uart_on_enter(void* context) {
3142
usb_uart_get_state(app->usb_uart_bridge, &scene_usb_uart->state);
3243

3344
gpio_usb_uart_set_callback(app->gpio_usb_uart, gpio_scene_usb_uart_callback, app);
34-
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, 0);
3545
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewUsbUart);
3646
notification_message(app->notifications, &sequence_display_backlight_enforce_on);
3747
}
3848

3949
bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
4050
GpioApp* app = context;
4151
if(event.type == SceneManagerEventTypeCustom) {
42-
scene_manager_set_scene_state(app->scene_manager, GpioSceneUsbUart, 1);
4352
scene_manager_next_scene(app->scene_manager, GpioSceneUsbUartCfg);
4453
return true;
4554
} else if(event.type == SceneManagerEventTypeBack) {
46-
scene_manager_next_scene(app->scene_manager, GpioSceneExitConfirm);
55+
DialogEx* dialog = app->dialog;
56+
dialog_ex_set_context(dialog, app);
57+
dialog_ex_set_left_button_text(dialog, "Exit");
58+
dialog_ex_set_right_button_text(dialog, "Stay");
59+
dialog_ex_set_header(dialog, "Exit USB-UART?", 22, 12, AlignLeft, AlignTop);
60+
dialog_ex_set_result_callback(dialog, gpio_scene_usb_uart_dialog_callback);
61+
view_dispatcher_switch_to_view(app->view_dispatcher, GpioAppViewExitConfirm);
4762
return true;
4863
} else if(event.type == SceneManagerEventTypeTick) {
4964
uint32_t tx_cnt_last = scene_usb_uart->state.tx_cnt;
@@ -61,10 +76,5 @@ bool gpio_scene_usb_uart_on_event(void* context, SceneManagerEvent event) {
6176

6277
void gpio_scene_usb_uart_on_exit(void* context) {
6378
GpioApp* app = context;
64-
uint32_t prev_state = scene_manager_get_scene_state(app->scene_manager, GpioSceneUsbUart);
65-
if(prev_state == 0) {
66-
usb_uart_disable(app->usb_uart_bridge);
67-
free(scene_usb_uart);
68-
}
6979
notification_message(app->notifications, &sequence_display_backlight_enforce_auto);
7080
}

applications/services/storage/storage.h

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -401,21 +401,26 @@ bool storage_common_exists(Storage* storage, const char* path);
401401
* - /int/Test and /int/test -> false (Case-sensitive storage),
402402
* - /ext/Test and /ext/test -> true (Case-insensitive storage).
403403
*
404-
* If the truncate parameter is set to true, the second path will be
405-
* truncated to be no longer than the first one. It is useful to determine
406-
* whether path2 is a subdirectory of path1.
407-
*
408404
* @param storage pointer to a storage API instance.
409405
* @param path1 pointer to a zero-terminated string containing the first path.
410406
* @param path2 pointer to a zero-terminated string containing the second path.
411-
* @param truncate whether to truncate path2 to be no longer than path1.
412407
* @return true if paths are equivalent, false otherwise.
413408
*/
414-
bool storage_common_equivalent_path(
415-
Storage* storage,
416-
const char* path1,
417-
const char* path2,
418-
bool truncate);
409+
bool storage_common_equivalent_path(Storage* storage, const char* path1, const char* path2);
410+
411+
/**
412+
* @brief Check whether a path is a subpath of another path.
413+
*
414+
* This function respects storage-defined equivalence rules
415+
* (see `storage_common_equivalent_path`).
416+
*
417+
* @param storage pointer to a storage API instance.
418+
* @param parent pointer to a zero-terminated string containing the parent path.
419+
* @param child pointer to a zero-terminated string containing the child path.
420+
* @return true if `child` is a subpath of `parent`, or if `child` is equivalent
421+
* to `parent`; false otherwise.
422+
*/
423+
bool storage_common_is_subdir(Storage* storage, const char* parent, const char* child);
419424

420425
/******************* Error Functions *******************/
421426

0 commit comments

Comments
 (0)