SC-F001 way better logging and parameters. not integrated yet but.
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
idf_component_register(SRC_DIRS "."
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES spi_flash unity test_utils littlefs spiffs fatfs esp_timer vfs)
|
||||
|
||||
target_add_binary_data(${COMPONENT_TARGET} "./testfs.bin" BINARY)
|
||||
@@ -0,0 +1 @@
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
255
managed_components/joltwallet__littlefs/test/test_benchmark.c
Normal file
255
managed_components/joltwallet__littlefs/test/test_benchmark.c
Normal file
@@ -0,0 +1,255 @@
|
||||
#include "test_littlefs_common.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
|
||||
static const char TAG[] = "[littlefs_benchmark]";
|
||||
|
||||
// Handle of the wear levelling library instance
|
||||
wl_handle_t s_wl_handle = WL_INVALID_HANDLE;
|
||||
#define MAX_FILES 5
|
||||
|
||||
static void setup_spiffs(){
|
||||
ESP_LOGI(TAG, "Initializing SPIFFS");
|
||||
|
||||
esp_spiffs_format("spiffs_store");
|
||||
|
||||
esp_vfs_spiffs_conf_t conf = {
|
||||
.base_path = "/spiffs",
|
||||
.partition_label = "spiffs_store",
|
||||
.max_files = MAX_FILES,
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
|
||||
esp_err_t ret = esp_vfs_spiffs_register(&conf);
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
ESP_LOGE(TAG, "Failed to mount or format filesystem");
|
||||
} else if (ret == ESP_ERR_NOT_FOUND) {
|
||||
ESP_LOGE(TAG, "Failed to find SPIFFS partition");
|
||||
} else {
|
||||
ESP_LOGE(TAG, "Failed to initialize SPIFFS (%s)", esp_err_to_name(ret));
|
||||
}
|
||||
TEST_FAIL();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_fat(){
|
||||
const esp_vfs_fat_mount_config_t conf = {
|
||||
.max_files = MAX_FILES,
|
||||
.format_if_mount_failed = true,
|
||||
.allocation_unit_size = CONFIG_WL_SECTOR_SIZE
|
||||
};
|
||||
esp_err_t err = esp_vfs_fat_spiflash_mount_rw_wl("/fat", "fat_store", &conf, &s_wl_handle);
|
||||
if (err != ESP_OK) {
|
||||
ESP_LOGE(TAG, "Failed to mount FATFS (%s)", esp_err_to_name(err));
|
||||
TEST_FAIL();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_littlefs() {
|
||||
esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = "/littlefs",
|
||||
.partition_label = "flash_test",
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
esp_littlefs_format("flash_test");
|
||||
}
|
||||
|
||||
static void test_benchmark_setup() {
|
||||
setup_fat();
|
||||
setup_spiffs();
|
||||
setup_littlefs();
|
||||
printf("Test setup complete.\n");
|
||||
}
|
||||
|
||||
static void test_benchmark_teardown()
|
||||
{
|
||||
assert(ESP_OK == esp_vfs_fat_spiflash_unmount_rw_wl("/fat", s_wl_handle));
|
||||
TEST_ESP_OK(esp_vfs_spiffs_unregister("spiffs_store"));
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister("flash_test"));
|
||||
printf("Test teardown complete.\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fill partitions with dummy data
|
||||
*/
|
||||
static void fill_partitions()
|
||||
{
|
||||
const esp_partition_t* part;
|
||||
const char dummy_data[] = {
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6',
|
||||
'D','U','M','M','Y','D','A','T','A','0','1','2', '3', '4', '5', '6'
|
||||
};
|
||||
|
||||
ESP_LOGI(TAG, "Filling SPIFFS partition with dummy data");
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY,
|
||||
"spiffs_store");
|
||||
esp_partition_erase_range(part, 0, part->size);
|
||||
for(uint32_t i=0; i < part->size; i += sizeof(dummy_data))
|
||||
esp_partition_write(part, i, dummy_data, sizeof(dummy_data));
|
||||
|
||||
ESP_LOGI(TAG, "Filling FAT partition with dummy data");
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY,
|
||||
"fat_store");
|
||||
esp_partition_erase_range(part, 0, part->size);
|
||||
for(uint32_t i=0; i < part->size; i += sizeof(dummy_data))
|
||||
esp_partition_write(part, i, dummy_data, sizeof(dummy_data));
|
||||
|
||||
ESP_LOGI(TAG, "Filling LittleFS partition with dummy data");
|
||||
part = esp_partition_find_first(ESP_PARTITION_TYPE_DATA, ESP_PARTITION_SUBTYPE_ANY,
|
||||
"flash_test");
|
||||
esp_partition_erase_range(part, 0, part->size);
|
||||
for(uint32_t i=0; i < part->size; i += sizeof(dummy_data))
|
||||
esp_partition_write(part, i, dummy_data, sizeof(dummy_data));
|
||||
}
|
||||
|
||||
static int get_file_size(const char *fname) {
|
||||
struct stat sb;
|
||||
|
||||
if( 0 != stat(fname, &sb) ) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sb.st_size;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Writes and deletes files
|
||||
* @param[in] mount_pt
|
||||
* @param[in] iter Number of files to write
|
||||
*/
|
||||
static void read_write_test_1(const char *mount_pt, uint32_t iter) {
|
||||
char fmt_fn[64] = { 0 };
|
||||
char fname[128] = { 0 };
|
||||
uint64_t t_write = 0;
|
||||
uint64_t t_read = 0;
|
||||
uint64_t t_delete = 0;
|
||||
|
||||
int n_write = 0;
|
||||
int n_read = 0;
|
||||
int n_delete = 0;
|
||||
|
||||
strcat(fmt_fn, mount_pt);
|
||||
if(fmt_fn[strlen(fmt_fn)-1] != '/') strcat(fmt_fn, "/");
|
||||
strcat(fmt_fn, "%d.txt");
|
||||
|
||||
/* WRITE */
|
||||
for(uint8_t i=0; i < iter; i++){
|
||||
snprintf(fname, sizeof(fname), fmt_fn, i);
|
||||
uint64_t t_start = esp_timer_get_time();
|
||||
FILE* f = fopen(fname, "w");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file %d for writing", i);
|
||||
continue;
|
||||
}
|
||||
for(uint32_t j=0; j < 2000; j++) {
|
||||
fprintf(f, "All work and no play makes Jack a dull boy.\n");
|
||||
}
|
||||
fclose(f);
|
||||
uint64_t t_end = esp_timer_get_time();
|
||||
int fsize = get_file_size(fname);
|
||||
printf("%d bytes written in %lld us\n", fsize, (t_end - t_start));
|
||||
t_write += (t_end - t_start);
|
||||
n_write += fsize;
|
||||
}
|
||||
|
||||
printf("------------\n");
|
||||
|
||||
/* READ */
|
||||
for(uint8_t i=0; i < iter; i++){
|
||||
int fsize = 0;
|
||||
snprintf(fname, sizeof(fname), fmt_fn, i);
|
||||
uint64_t t_start = esp_timer_get_time();
|
||||
FILE* f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
ESP_LOGE(TAG, "Failed to open file %d for reading", i);
|
||||
continue;
|
||||
}
|
||||
|
||||
while(fgetc(f) != EOF) fsize ++;
|
||||
|
||||
fclose(f);
|
||||
uint64_t t_end = esp_timer_get_time();
|
||||
printf("%d bytes read in %lld us\n", fsize, (t_end - t_start));
|
||||
t_read += (t_end - t_start);
|
||||
n_read += fsize;
|
||||
}
|
||||
|
||||
printf("------------\n");
|
||||
|
||||
/* DELETE */
|
||||
for(uint8_t i=0; i < iter; i++){
|
||||
snprintf(fname, sizeof(fname), fmt_fn, i);
|
||||
|
||||
int fsize = get_file_size(fname);
|
||||
if (fsize < 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uint64_t t_start = esp_timer_get_time();
|
||||
snprintf(fname, sizeof(fname), fmt_fn, i);
|
||||
unlink(fname);
|
||||
uint64_t t_end = esp_timer_get_time();
|
||||
printf("deleted file %d in %lld us\n", i, (t_end - t_start));
|
||||
t_delete += (t_end - t_start);
|
||||
n_delete += fsize;
|
||||
}
|
||||
|
||||
printf("------------\n");
|
||||
|
||||
printf("Total (%d) Write: %lld us\n", n_write, t_write);
|
||||
printf("Total (%d) Read: %lld us\n", n_read, t_read);
|
||||
printf("Total (%d) Delete: %lld us\n", n_delete, t_delete);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("Format", TAG){
|
||||
uint64_t t_fat, t_spiffs, t_littlefs, t_start;
|
||||
|
||||
fill_partitions();
|
||||
|
||||
t_start = esp_timer_get_time();
|
||||
esp_spiffs_format(NULL);
|
||||
t_spiffs = esp_timer_get_time() - t_start;
|
||||
printf("SPIFFS Formatted in %lld us\n", t_spiffs);
|
||||
|
||||
t_start = esp_timer_get_time();
|
||||
setup_fat();
|
||||
assert(ESP_OK == esp_vfs_fat_spiflash_unmount("/fat", s_wl_handle));
|
||||
t_fat = esp_timer_get_time() - t_start;
|
||||
printf("FAT Formatted in %lld us\n", t_fat);
|
||||
|
||||
t_start = esp_timer_get_time();
|
||||
esp_littlefs_format("flash_test");
|
||||
t_littlefs = esp_timer_get_time() - t_start;
|
||||
printf("LittleFS Formatted in %lld us\n", t_littlefs);
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Write 5 files, read 5 files, then delete 5 files", TAG){
|
||||
test_benchmark_setup();
|
||||
|
||||
printf("FAT:\n");
|
||||
read_write_test_1("/fat", 5);
|
||||
printf("\n");
|
||||
|
||||
printf("SPIFFS:\n");
|
||||
read_write_test_1("/spiffs", 5);
|
||||
printf("\n");
|
||||
|
||||
printf("LittleFS:\n");
|
||||
read_write_test_1("/littlefs", 5);
|
||||
printf("\n");
|
||||
|
||||
test_benchmark_teardown();
|
||||
}
|
||||
342
managed_components/joltwallet__littlefs/test/test_dir.c
Normal file
342
managed_components/joltwallet__littlefs/test/test_dir.c
Normal file
@@ -0,0 +1,342 @@
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#ifdef CONFIG_VFS_SUPPORT_DIR
|
||||
|
||||
#include "test_littlefs_common.h"
|
||||
|
||||
//#define LOG_LOCAL_LEVEL 4
|
||||
|
||||
TEST_CASE("truncate", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
FILE* f;
|
||||
char buf[10] = { 0 };
|
||||
const char fn[] = littlefs_base_path "/truncate.txt";
|
||||
|
||||
f = fopen(fn, "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(11, fprintf(f, "0123456789\n"));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, truncate(fn, 3));
|
||||
|
||||
f = fopen(fn, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(3, fread(buf, 1, 8, f));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("012", buf, 8);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
#ifdef ESP_LITTLEFS_ENABLE_FTRUNCATE
|
||||
TEST_CASE("ftruncate", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
int fd;
|
||||
FILE* f;
|
||||
char buf[10] = { 0 };
|
||||
const char fn[] = littlefs_base_path "/truncate.txt";
|
||||
|
||||
f = fopen(fn, "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(11, fprintf(f, "0123456789\n"));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
fd = open(fn, O_RDWR);
|
||||
TEST_ASSERT_EQUAL(0, ftruncate(fd, 3));
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
|
||||
|
||||
f = fopen(fn, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(3, fread(buf, 1, 8, f));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("012", buf, 8);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
#endif // ESP_LITTLEFS_ENABLE_FTRUNCATE
|
||||
|
||||
|
||||
static void test_littlefs_readdir_many_files(const char* dir_prefix)
|
||||
{
|
||||
const int n_files = 40;
|
||||
const int n_folders = 4;
|
||||
unsigned char file_count[n_files * n_folders];
|
||||
memset(file_count, 0, sizeof(file_count)/sizeof(file_count[0]));
|
||||
char file_name[ESP_VFS_PATH_MAX + CONFIG_LITTLEFS_OBJ_NAME_LEN];
|
||||
|
||||
/* clean stale files before the test */
|
||||
mkdir(dir_prefix, 0755);
|
||||
DIR* dir = opendir(dir_prefix);
|
||||
if (dir) {
|
||||
while (true) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
int len = snprintf(file_name, sizeof(file_name), "%s/%s", dir_prefix, de->d_name);
|
||||
assert(len < sizeof(file_name));
|
||||
unlink(file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* create files */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("filling directory %d\n", d);
|
||||
snprintf(file_name, sizeof(file_name), "%s/%d", dir_prefix, d);
|
||||
mkdir( file_name, 0755 );
|
||||
for (int f = 0; f < n_files; ++f) {
|
||||
snprintf(file_name, sizeof(file_name), "%s/%d/%d.txt", dir_prefix, d, f);
|
||||
test_littlefs_create_file_with_text(file_name, file_name);
|
||||
}
|
||||
}
|
||||
|
||||
/* list files */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("listing files in directory %d\n", d);
|
||||
snprintf(file_name, sizeof(file_name), "%s/%d", dir_prefix, d);
|
||||
dir = opendir(file_name);
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
while (true) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
int file_id;
|
||||
TEST_ASSERT_EQUAL(1, sscanf(de->d_name, "%d.txt", &file_id));
|
||||
file_count[file_id + d * n_files]++;
|
||||
}
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
/* check that all created files have been seen */
|
||||
for (int d = 0; d < n_folders; ++d) {
|
||||
printf("checking that all files have been found in directory %d\n", d);
|
||||
for (int f = 0; f < n_files; ++f) {
|
||||
TEST_ASSERT_EQUAL(1, file_count[f + d * n_files]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("mkdir, rmdir", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
const char filename_prefix[] = littlefs_base_path "/";
|
||||
|
||||
char name_dir1[64];
|
||||
char name_dir2[64];
|
||||
char name_dir2_file[64];
|
||||
|
||||
snprintf(name_dir1, sizeof(name_dir1), "%s1", filename_prefix);
|
||||
snprintf(name_dir2, sizeof(name_dir2), "%s2", filename_prefix);
|
||||
snprintf(name_dir2_file, sizeof(name_dir2_file), "%s2/1.txt", filename_prefix);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, mkdir(name_dir1, 0755));
|
||||
struct stat st;
|
||||
TEST_ASSERT_EQUAL(0, stat(name_dir1, &st));
|
||||
TEST_ASSERT_TRUE(st.st_mode & S_IFDIR);
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFREG);
|
||||
TEST_ASSERT_EQUAL(0, rmdir(name_dir1));
|
||||
|
||||
// Attempt to stat a removed directory
|
||||
TEST_ASSERT_EQUAL(-1, stat(name_dir1, &st));
|
||||
TEST_ASSERT_EQUAL(ENOENT, errno);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, mkdir(name_dir2, 0755));
|
||||
test_littlefs_create_file_with_text(name_dir2_file, "foo\n");
|
||||
TEST_ASSERT_EQUAL(0, stat(name_dir2, &st));
|
||||
TEST_ASSERT_TRUE(st.st_mode & S_IFDIR);
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFREG);
|
||||
TEST_ASSERT_EQUAL(0, stat(name_dir2_file, &st));
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFDIR);
|
||||
TEST_ASSERT_TRUE(st.st_mode & S_IFREG);
|
||||
|
||||
// Can't remove directory, its not empty
|
||||
TEST_ASSERT_EQUAL(-1, rmdir(name_dir2));
|
||||
TEST_ASSERT_EQUAL(ENOTEMPTY, errno);
|
||||
|
||||
TEST_ASSERT_EQUAL(0, unlink(name_dir2_file));
|
||||
#if !CONFIG_LITTLEFS_SPIFFS_COMPAT
|
||||
/* this will have already been deleted */
|
||||
TEST_ASSERT_EQUAL(0, rmdir(name_dir2));
|
||||
#endif
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("opendir, readdir, rewinddir, seekdir work as expected", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
const char dir_prefix[] = littlefs_base_path "/dir";
|
||||
|
||||
char name_dir_inner_file[64];
|
||||
char name_dir_inner[64];
|
||||
char name_dir_file3[64];
|
||||
char name_dir_file2[64];
|
||||
char name_dir_file1[64];
|
||||
|
||||
snprintf(name_dir_inner_file, sizeof(name_dir_inner_file), "%s/inner/3.txt", dir_prefix);
|
||||
snprintf(name_dir_inner, sizeof(name_dir_inner), "%s/inner", dir_prefix);
|
||||
snprintf(name_dir_file3, sizeof(name_dir_file2), "%s/boo.bin", dir_prefix);
|
||||
snprintf(name_dir_file2, sizeof(name_dir_file2), "%s/2.txt", dir_prefix);
|
||||
snprintf(name_dir_file1, sizeof(name_dir_file1), "%s/1.txt", dir_prefix);
|
||||
|
||||
/* Remove files/dirs that may exist */
|
||||
unlink(name_dir_inner_file);
|
||||
rmdir(name_dir_inner);
|
||||
unlink(name_dir_file1);
|
||||
unlink(name_dir_file2);
|
||||
unlink(name_dir_file3);
|
||||
rmdir(dir_prefix);
|
||||
|
||||
/* Create the files */
|
||||
TEST_ASSERT_EQUAL(0, mkdir(dir_prefix, 0755));
|
||||
TEST_ASSERT_EQUAL(0, mkdir(name_dir_inner, 0755));
|
||||
test_littlefs_create_file_with_text(name_dir_file1, "1\n");
|
||||
test_littlefs_create_file_with_text(name_dir_file2, "2\n");
|
||||
test_littlefs_create_file_with_text(name_dir_file3, "\01\02\03");
|
||||
test_littlefs_create_file_with_text(name_dir_inner_file, "3\n");
|
||||
|
||||
DIR* dir = opendir(dir_prefix);
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
int count = 0;
|
||||
const char* names[4];
|
||||
while( true ) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(de->d_name, "1.txt") == 0) {
|
||||
TEST_ASSERT_TRUE(de->d_type == DT_REG);
|
||||
names[count] = "1.txt";
|
||||
++count;
|
||||
} else if (strcasecmp(de->d_name, "2.txt") == 0) {
|
||||
TEST_ASSERT_TRUE(de->d_type == DT_REG);
|
||||
names[count] = "2.txt";
|
||||
++count;
|
||||
} else if (strcasecmp(de->d_name, "inner") == 0) {
|
||||
TEST_ASSERT_TRUE(de->d_type == DT_DIR);
|
||||
names[count] = "inner";
|
||||
++count;
|
||||
} else if (strcasecmp(de->d_name, "boo.bin") == 0) {
|
||||
TEST_ASSERT_TRUE(de->d_type == DT_REG);
|
||||
names[count] = "boo.bin";
|
||||
++count;
|
||||
} else {
|
||||
char buf[512] = { 0 };
|
||||
snprintf(buf, sizeof(buf), "unexpected directory entry \"%s\"", de->d_name);
|
||||
TEST_FAIL_MESSAGE(buf);
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_EQUAL(count, 4);
|
||||
|
||||
rewinddir(dir);
|
||||
struct dirent* de = readdir(dir);
|
||||
TEST_ASSERT_NOT_NULL(de);
|
||||
TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[0]));
|
||||
seekdir(dir, 3);
|
||||
de = readdir(dir);
|
||||
TEST_ASSERT_NOT_NULL(de);
|
||||
TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[3]));
|
||||
seekdir(dir, 1);
|
||||
de = readdir(dir);
|
||||
TEST_ASSERT_NOT_NULL(de);
|
||||
TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[1]));
|
||||
seekdir(dir, 2);
|
||||
de = readdir(dir);
|
||||
TEST_ASSERT_NOT_NULL(de);
|
||||
TEST_ASSERT_EQUAL(0, strcasecmp(de->d_name, names[2]));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, closedir(dir));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("readdir with large number of files", "[littlefs][timeout=30]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_readdir_many_files(littlefs_base_path "/dir2");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can opendir root directory of FS", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
const char path[] = littlefs_base_path;
|
||||
|
||||
char name_dir_file[64];
|
||||
const char * file_name = "test_opd.txt";
|
||||
snprintf(name_dir_file, sizeof(name_dir_file), "%s/%s", path, file_name);
|
||||
unlink(name_dir_file);
|
||||
test_littlefs_create_file_with_text(name_dir_file, "test_opendir\n");
|
||||
DIR* dir = opendir(path);
|
||||
TEST_ASSERT_NOT_NULL(dir);
|
||||
bool found = false;
|
||||
while (true) {
|
||||
struct dirent* de = readdir(dir);
|
||||
if (!de) {
|
||||
break;
|
||||
}
|
||||
if (strcasecmp(de->d_name, file_name) == 0) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_TRUE(found);
|
||||
TEST_ASSERT_EQUAL(0, closedir(dir));
|
||||
unlink(name_dir_file);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("unlink removes a file", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
const char filename[] = littlefs_base_path "/unlink.txt";
|
||||
|
||||
test_littlefs_create_file_with_text(filename, "unlink\n");
|
||||
TEST_ASSERT_EQUAL(0, unlink(filename));
|
||||
TEST_ASSERT_NULL(fopen(filename, "r"));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("rename moves a file", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
const char filename_prefix[] = littlefs_base_path "/move";
|
||||
|
||||
char name_dst[64];
|
||||
char name_src[64];
|
||||
snprintf(name_dst, sizeof(name_dst), "%s_dst.txt", filename_prefix);
|
||||
snprintf(name_src, sizeof(name_src), "%s_src.txt", filename_prefix);
|
||||
|
||||
unlink(name_dst);
|
||||
unlink(name_src);
|
||||
|
||||
FILE* f = fopen(name_src, "w+");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
const char* str = "0123456789";
|
||||
for (int i = 0; i < 400; ++i) {
|
||||
TEST_ASSERT_NOT_EQUAL(EOF, fputs(str, f));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
TEST_ASSERT_EQUAL(0, rename(name_src, name_dst));
|
||||
TEST_ASSERT_NULL(fopen(name_src, "r"));
|
||||
FILE* fdst = fopen(name_dst, "r");
|
||||
TEST_ASSERT_NOT_NULL(fdst);
|
||||
TEST_ASSERT_EQUAL(0, fseek(fdst, 0, SEEK_END));
|
||||
TEST_ASSERT_EQUAL(4000, ftell(fdst));
|
||||
TEST_ASSERT_EQUAL(0, fclose(fdst));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
941
managed_components/joltwallet__littlefs/test/test_littlefs.c
Normal file
941
managed_components/joltwallet__littlefs/test/test_littlefs.c
Normal file
@@ -0,0 +1,941 @@
|
||||
//#define LOG_LOCAL_LEVEL 4
|
||||
#include "test_littlefs_common.h"
|
||||
|
||||
static void test_littlefs_write_file_with_offset(const char *filename);
|
||||
static void test_littlefs_read_file_with_offset(const char *filename);
|
||||
static void test_littlefs_overwrite_append(const char* filename);
|
||||
static void test_littlefs_open_max_files(const char* filename_prefix, size_t files_count);
|
||||
static void test_littlefs_concurrent_rw(const char* filename_prefix);
|
||||
|
||||
static int test_littlefs_stat(const char *path, struct stat *buf);
|
||||
|
||||
TEST_CASE("can initialize LittleFS in erased partition", "[littlefs]")
|
||||
{
|
||||
/* Gets the partition labeled "flash_test" */
|
||||
const esp_partition_t* part = get_test_data_partition();
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
TEST_ESP_OK(esp_partition_erase_range(part, 0, part->size));
|
||||
test_setup();
|
||||
size_t total = 0, used = 0;
|
||||
TEST_ESP_OK(esp_littlefs_info(littlefs_test_partition_label, &total, &used));
|
||||
printf("total: %d, used: %d\n", total, used);
|
||||
TEST_ASSERT_EQUAL(8192, used); // 2 blocks are used on a fresh filesystem
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can format mounted partition", "[littlefs]")
|
||||
{
|
||||
// Mount LittleFS, create file, format, check that the file does not exist.
|
||||
const esp_partition_t* part = get_test_data_partition();
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
test_setup();
|
||||
const char* filename = littlefs_base_path "/hello.txt";
|
||||
test_littlefs_create_file_with_text(filename, littlefs_test_hello_str);
|
||||
printf("Deleting \"%s\" via formatting fs.\n", filename);
|
||||
esp_littlefs_format(part->label);
|
||||
FILE* f = fopen(filename, "r");
|
||||
TEST_ASSERT_NULL(f);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can format unmounted partition", "[littlefs]")
|
||||
{
|
||||
// Mount LittleFS, create file, unmount. Format. Mount again, check that
|
||||
// the file does not exist.
|
||||
const esp_partition_t* part = get_test_data_partition();
|
||||
TEST_ASSERT_NOT_NULL(part);
|
||||
|
||||
test_setup();
|
||||
const char* filename = littlefs_base_path "/hello.txt";
|
||||
test_littlefs_create_file_with_text(filename, littlefs_test_hello_str);
|
||||
test_teardown();
|
||||
|
||||
esp_littlefs_format(part->label);
|
||||
// Don't use test_setup here, need to mount without formatting
|
||||
const esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = littlefs_base_path,
|
||||
.partition_label = littlefs_test_partition_label,
|
||||
.format_if_mount_failed = false
|
||||
};
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
|
||||
FILE* f = fopen(filename, "r");
|
||||
TEST_ASSERT_NULL(f);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("NULL label mounts first littlefs partition.", "[littlefs]")
|
||||
{
|
||||
esp_littlefs_format(littlefs_test_partition_label);
|
||||
const esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = littlefs_base_path,
|
||||
.partition_label = NULL,
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
|
||||
TEST_ASSERT_TRUE( esp_littlefs_mounted(NULL) );
|
||||
TEST_ASSERT_TRUE( esp_littlefs_mounted("named_part") );
|
||||
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister(NULL));
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
}
|
||||
|
||||
TEST_CASE("can create and write file", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_create_file_with_text(littlefs_base_path "/hello.txt", littlefs_test_hello_str);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can read file", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_create_file_with_text(littlefs_base_path "/hello.txt", littlefs_test_hello_str);
|
||||
test_littlefs_read_file(littlefs_base_path "/hello.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can write to file with offset (pwrite)", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_write_file_with_offset(littlefs_base_path "/hello.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can read from file with offset (pread)", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_read_file_with_offset(littlefs_base_path "/hello.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("r+ mode read and write file", "[littlefs]")
|
||||
{
|
||||
/* Note: despite some online resources, "r+" should not create a file
|
||||
* if it does not exist */
|
||||
|
||||
const char fn[] = littlefs_base_path "/hello.txt";
|
||||
char buf[100] = { 0 };
|
||||
|
||||
test_setup();
|
||||
|
||||
test_littlefs_create_file_with_text(fn, "foo");
|
||||
|
||||
/* Read back the previously written foo, and add bar*/
|
||||
{
|
||||
FILE* f = fopen(fn, "r+");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(3, fread(buf, 1, sizeof(buf), f));
|
||||
TEST_ASSERT_EQUAL_STRING("foo", buf);
|
||||
TEST_ASSERT_TRUE(fputs("bar", f) != EOF);
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_SET));
|
||||
TEST_ASSERT_EQUAL(6, fread(buf, 1, 6, f));
|
||||
TEST_ASSERT_EQUAL_STRING("foobar", buf);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
/* Just normal read the whole contents */
|
||||
{
|
||||
FILE* f = fopen(fn, "r+");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(6, fread(buf, 1, sizeof(buf), f));
|
||||
TEST_ASSERT_EQUAL_STRING("foobar", buf);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("w+ mode read and write file", "[littlefs]")
|
||||
{
|
||||
const char fn[] = littlefs_base_path "/hello.txt";
|
||||
char buf[100] = { 0 };
|
||||
|
||||
test_setup();
|
||||
|
||||
test_littlefs_create_file_with_text(fn, "foo");
|
||||
|
||||
/* this should overwrite the file and be readable */
|
||||
{
|
||||
FILE* f = fopen(fn, "w+");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_TRUE(fputs("bar", f) != EOF);
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_SET));
|
||||
TEST_ASSERT_EQUAL(3, fread(buf, 1, sizeof(buf), f));
|
||||
TEST_ASSERT_EQUAL_STRING("bar", buf);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
|
||||
TEST_CASE("can open maximum number of files", "[littlefs]")
|
||||
{
|
||||
size_t max_files = FOPEN_MAX - 3; /* account for stdin, stdout, stderr, esp-idf defaults to maximum 64 file descriptors */
|
||||
|
||||
test_setup();
|
||||
test_littlefs_open_max_files("/littlefs/f", max_files);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("overwrite and append file", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_overwrite_append(littlefs_base_path "/hello.txt");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("use append with other flags", "[littlefs]")
|
||||
{
|
||||
// https://github.com/joltwallet/esp_littlefs/issues/154
|
||||
test_setup();
|
||||
|
||||
int fd;
|
||||
|
||||
fd = open(littlefs_base_path "/fcntl.txt", O_CREAT | O_WRONLY | O_TRUNC, 0777);
|
||||
TEST_ASSERT_EQUAL(6, write(fd, "test1\n", 6));
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
|
||||
fd = open(littlefs_base_path "/fcntl.txt", O_CREAT | O_WRONLY | O_APPEND, 0777);
|
||||
TEST_ASSERT_EQUAL(0, lseek(fd, 0, SEEK_CUR));
|
||||
TEST_ASSERT_EQUAL(6, write(fd, "test2\n", 6));
|
||||
TEST_ASSERT_EQUAL(12, lseek(fd, 0, SEEK_CUR));
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("can lseek", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
FILE* f = fopen(littlefs_base_path "/seek.txt", "wb+");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(11, fprintf(f, "0123456789\n"));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, -2, SEEK_CUR));
|
||||
TEST_ASSERT_EQUAL('9', fgetc(f));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 3, SEEK_SET));
|
||||
TEST_ASSERT_EQUAL('3', fgetc(f));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, -3, SEEK_END));
|
||||
TEST_ASSERT_EQUAL('8', fgetc(f));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
|
||||
TEST_ASSERT_EQUAL(11, ftell(f));
|
||||
// Appending to end
|
||||
TEST_ASSERT_EQUAL(4, fprintf(f, "abc\n"));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_END));
|
||||
TEST_ASSERT_EQUAL(15, ftell(f));
|
||||
// Appending past end of file, creating a "hole"
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 2, SEEK_END));
|
||||
TEST_ASSERT_EQUAL(4, fprintf(f, "foo\n"));
|
||||
TEST_ASSERT_EQUAL(0, fseek(f, 0, SEEK_SET));
|
||||
char buf[32];
|
||||
TEST_ASSERT_EQUAL(21, fread(buf, 1, sizeof(buf), f));
|
||||
const char ref_buf[] = "0123456789\nabc\n\0\0foo\n";
|
||||
TEST_ASSERT_EQUAL_INT8_ARRAY(ref_buf, buf, sizeof(ref_buf) - 1);
|
||||
|
||||
// Error checking
|
||||
// Attempting to seek before the beginning of file should return an error
|
||||
TEST_ASSERT_EQUAL(-1, fseek(f, 100, 100)); // Bad mode
|
||||
TEST_ASSERT_EQUAL(EINVAL, errno);
|
||||
TEST_ASSERT_EQUAL(-1, fseek(f, -1, SEEK_SET)); // Seeking to before start of file
|
||||
TEST_ASSERT_EQUAL(EINVAL, errno);
|
||||
|
||||
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("stat/fstat returns correct values", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
const char filename[] = littlefs_base_path "/stat.txt";
|
||||
|
||||
test_littlefs_create_file_with_text(filename, "foo\n");
|
||||
struct stat st;
|
||||
for(uint8_t i=0; i < 2; i++) {
|
||||
if(i == 0){
|
||||
// Test stat
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
}
|
||||
else {
|
||||
#ifndef CONFIG_LITTLEFS_USE_ONLY_HASH
|
||||
// Test fstat
|
||||
FILE *f = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_EQUAL(0, fstat(fileno(f), &st));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
#endif
|
||||
}
|
||||
TEST_ASSERT(st.st_mode & S_IFREG);
|
||||
TEST_ASSERT_FALSE(st.st_mode & S_IFDIR);
|
||||
TEST_ASSERT_EQUAL(4, st.st_size);
|
||||
}
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("multiple tasks can use same volume", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
test_littlefs_concurrent_rw(littlefs_base_path "/f");
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("esp_littlefs_info", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
char filename[] = littlefs_base_path "/test_esp_littlefs_info.bin";
|
||||
unlink(filename); /* Delete the file incase it exists */
|
||||
|
||||
/* Get starting system size */
|
||||
size_t total_og = 0, used_og = 0;
|
||||
TEST_ESP_OK(esp_littlefs_info(littlefs_test_partition_label, &total_og, &used_og));
|
||||
|
||||
/* Write 100,000 bytes */
|
||||
FILE* f = fopen(filename, "wb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char val = 'c';
|
||||
size_t n_bytes = 100000;
|
||||
for(int i=0; i < n_bytes; i++) {
|
||||
TEST_ASSERT_EQUAL(1, fwrite(&val, 1, 1, f));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
/* Re-check system size */
|
||||
size_t total_new = 0, used_new = 0;
|
||||
TEST_ESP_OK(esp_littlefs_info(littlefs_test_partition_label, &total_new, &used_new));
|
||||
|
||||
printf("old: %d; new: %d; diff: %d\n", used_og, used_new, used_new-used_og);
|
||||
|
||||
/* total amount of storage shouldn't change */
|
||||
TEST_ASSERT_EQUAL_INT(total_og, total_new);
|
||||
|
||||
/* The actual amount of used storage should be within 2 blocks of expected.*/
|
||||
size_t diff = used_new - used_og;
|
||||
TEST_ASSERT_GREATER_THAN_INT(n_bytes - (2 * 4096), diff);
|
||||
TEST_ASSERT_LESS_THAN_INT(n_bytes + (2 * 4096), diff);
|
||||
|
||||
unlink(filename);
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
#if CONFIG_LITTLEFS_USE_MTIME
|
||||
|
||||
#if CONFIG_LITTLEFS_MTIME_USE_SECONDS
|
||||
TEST_CASE("mtime support", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
/* Open a file, check that mtime is set correctly */
|
||||
const char* filename = littlefs_base_path "/time";
|
||||
time_t t_before_create = time(NULL);
|
||||
test_littlefs_create_file_with_text(filename, "test");
|
||||
time_t t_after_create = time(NULL);
|
||||
|
||||
struct stat st;
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT(st.st_mtime >= t_before_create);
|
||||
TEST_ASSERT(st.st_mtime <= t_after_create);
|
||||
|
||||
/* Wait a bit, open & close again, check that mtime is updated */
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
time_t t_before_close = time(NULL);
|
||||
FILE *f = fopen(filename, "a");
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
time_t t_after_close = time(NULL);
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
time_t append_mtime = st.st_mtime;
|
||||
TEST_ASSERT(append_mtime >= t_before_close);
|
||||
TEST_ASSERT(append_mtime <= t_after_close);
|
||||
|
||||
/* Wait a bit, open for reading, check that mtime is not updated */
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
time_t t_before_close_ro = time(NULL);
|
||||
f = fopen(filename, "r");
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT(t_before_close_ro > t_after_close); // sufficient time has passed for this test to be valid.
|
||||
// make sure the st_mtime is the same as bfore
|
||||
TEST_ASSERT(st.st_mtime == append_mtime);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if CONFIG_LITTLEFS_MTIME_USE_NONCE
|
||||
TEST_CASE("mnonce support", "[littlefs]")
|
||||
{
|
||||
/* Open a file, check that mtime is set correctly */
|
||||
struct stat st;
|
||||
const char* filename = littlefs_base_path "/time";
|
||||
test_setup();
|
||||
test_littlefs_create_file_with_text(filename, "test");
|
||||
|
||||
int nonce1;
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
nonce1 = (int) st.st_mtime;
|
||||
printf("mtime=%d\n", nonce1);
|
||||
TEST_ASSERT(nonce1 >= 0);
|
||||
|
||||
/* open again, check that mtime is updated */
|
||||
int nonce2;
|
||||
FILE *f = fopen(filename, "a");
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
nonce2 = (int) st.st_mtime;
|
||||
printf("mtime=%d\n", nonce2);
|
||||
if( nonce1 == UINT32_MAX ) {
|
||||
TEST_ASSERT_EQUAL_INT(1, nonce2);
|
||||
}
|
||||
else {
|
||||
TEST_ASSERT_EQUAL_INT(1, nonce2-nonce1);
|
||||
}
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
/* open for reading, check that mtime is not updated */
|
||||
int nonce3;
|
||||
f = fopen(filename, "r");
|
||||
TEST_ASSERT_EQUAL(0, test_littlefs_stat(filename, &st));
|
||||
nonce3 = (int) st.st_mtime;
|
||||
printf("mtime=%d\n", (int) st.st_mtime);
|
||||
TEST_ASSERT_EQUAL_INT(nonce2, nonce3);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
static void test_littlefs_write_file_with_offset(const char *filename)
|
||||
{
|
||||
const char *source = "Replace this character: [k]";
|
||||
off_t offset = strstr(source, "k") - source;
|
||||
size_t len = strlen(source);
|
||||
const char new_char = 'y';
|
||||
|
||||
// Create file with string at source string
|
||||
test_littlefs_create_file_with_text(filename, source);
|
||||
|
||||
// Replace k with y at the file
|
||||
int fd = open(filename, O_RDWR);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
int written = pwrite(fd, &new_char, 1, offset);
|
||||
TEST_ASSERT_EQUAL(1, written);
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
|
||||
char buf[len];
|
||||
|
||||
// Compare if both are equal
|
||||
FILE *f = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
int rd = fread(buf, len, 1, f);
|
||||
TEST_ASSERT_EQUAL(1, rd);
|
||||
TEST_ASSERT_EQUAL(buf[offset], new_char);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
static void test_littlefs_read_file_with_offset(const char *filename)
|
||||
{
|
||||
const char *source = "This text will be partially read";
|
||||
off_t offset = strstr(source, "p") - source;
|
||||
size_t len = strlen(source);
|
||||
char buf[len - offset + 1];
|
||||
buf[len-offset] = '\0'; // EOS
|
||||
|
||||
// Create file with string at source string
|
||||
test_littlefs_create_file_with_text(filename, source);
|
||||
|
||||
// Read file content beginning at `partially` word
|
||||
int fd = open(filename, O_RDONLY);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
int rd = pread(fd, buf, len - offset, offset);
|
||||
TEST_ASSERT_EQUAL(len - offset, rd);
|
||||
// Compare if string read from file and source string related slice are equal
|
||||
int res = strcmp(buf, &source[offset]);
|
||||
TEST_ASSERT_EQUAL(0, res);
|
||||
TEST_ASSERT_EQUAL(0, close(fd));
|
||||
}
|
||||
|
||||
static void test_littlefs_overwrite_append(const char* filename)
|
||||
{
|
||||
/* Create new file with 'aaaa' */
|
||||
test_littlefs_create_file_with_text(filename, "aaaa");
|
||||
|
||||
/* Append 'bbbb' to file */
|
||||
FILE *f_a = fopen(filename, "a");
|
||||
TEST_ASSERT_NOT_NULL(f_a);
|
||||
TEST_ASSERT_NOT_EQUAL(EOF, fputs("bbbb", f_a));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f_a));
|
||||
|
||||
/* Read back 8 bytes from file, verify it's 'aaaabbbb' */
|
||||
char buf[10] = { 0 };
|
||||
FILE *f_r = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f_r);
|
||||
TEST_ASSERT_EQUAL(8, fread(buf, 1, 8, f_r));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("aaaabbbb", buf, 8);
|
||||
|
||||
/* Be sure we're at end of file */
|
||||
TEST_ASSERT_EQUAL(0, fread(buf, 1, 8, f_r));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, fclose(f_r));
|
||||
|
||||
/* Overwrite file with 'cccc' */
|
||||
test_littlefs_create_file_with_text(filename, "cccc");
|
||||
|
||||
/* Verify file now only contains 'cccc' */
|
||||
f_r = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f_r);
|
||||
bzero(buf, sizeof(buf));
|
||||
TEST_ASSERT_EQUAL(4, fread(buf, 1, 8, f_r)); // trying to read 8 bytes, only expecting 4
|
||||
TEST_ASSERT_EQUAL_STRING_LEN("cccc", buf, 4);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f_r));
|
||||
}
|
||||
|
||||
static void test_littlefs_open_max_files(const char* filename_prefix, size_t files_count)
|
||||
{
|
||||
FILE** files = calloc(files_count, sizeof(FILE*));
|
||||
assert(files);
|
||||
for (size_t i = 0; i < files_count; ++i) {
|
||||
char name[32];
|
||||
snprintf(name, sizeof(name), "%s_%d.txt", filename_prefix, i);
|
||||
printf("Opening \"%s\"\n", name);
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
files[i] = fopen(name, "w");
|
||||
TEST_ASSERT_NOT_NULL(files[i]);
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
}
|
||||
/* close everything and clean up */
|
||||
for (size_t i = 0; i < files_count; ++i) {
|
||||
TEST_ASSERT_EQUAL(0, fclose(files[i]));
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
}
|
||||
free(files);
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
CONCURRENT_TASK_ACTION_READ,
|
||||
CONCURRENT_TASK_ACTION_WRITE,
|
||||
CONCURRENT_TASK_ACTION_STAT,
|
||||
} concurrent_task_action_t;
|
||||
|
||||
typedef struct {
|
||||
const char* filename;
|
||||
concurrent_task_action_t action;
|
||||
size_t word_count;
|
||||
int seed;
|
||||
SemaphoreHandle_t done;
|
||||
int result;
|
||||
} read_write_test_arg_t;
|
||||
|
||||
#define READ_WRITE_TEST_ARG_INIT(name, seed_) \
|
||||
{ \
|
||||
.filename = name, \
|
||||
.seed = seed_, \
|
||||
.word_count = 4096, \
|
||||
.action = CONCURRENT_TASK_ACTION_WRITE, \
|
||||
.done = xSemaphoreCreateBinary() \
|
||||
}
|
||||
|
||||
static void read_write_task(void* param)
|
||||
{
|
||||
FILE *f = NULL;
|
||||
read_write_test_arg_t* args = (read_write_test_arg_t*) param;
|
||||
if (args->action == CONCURRENT_TASK_ACTION_WRITE) {
|
||||
f = fopen(args->filename, "wb");
|
||||
if (f == NULL) {args->result = ESP_ERR_NOT_FOUND; goto done;}
|
||||
} else if (args->action == CONCURRENT_TASK_ACTION_READ) {
|
||||
f = fopen(args->filename, "rb");
|
||||
if (f == NULL) {args->result = ESP_ERR_NOT_FOUND; goto done;}
|
||||
} else if (args->action == CONCURRENT_TASK_ACTION_STAT) {
|
||||
}
|
||||
|
||||
srand(args->seed);
|
||||
for (size_t i = 0; i < args->word_count; ++i) {
|
||||
uint32_t val = rand();
|
||||
if (args->action == CONCURRENT_TASK_ACTION_WRITE) {
|
||||
int cnt = fwrite(&val, sizeof(val), 1, f);
|
||||
if (cnt != 1) {
|
||||
esp_rom_printf("E(w): i=%d, cnt=%d val=%d\n\n", i, cnt, val);
|
||||
args->result = ESP_FAIL;
|
||||
goto close;
|
||||
}
|
||||
} else if (args->action == CONCURRENT_TASK_ACTION_READ) {
|
||||
uint32_t rval;
|
||||
int cnt = fread(&rval, sizeof(rval), 1, f);
|
||||
if (cnt != 1) {
|
||||
esp_rom_printf("E(r): i=%d, cnt=%d rval=%d\n\n", i, cnt, rval);
|
||||
args->result = ESP_FAIL;
|
||||
goto close;
|
||||
}
|
||||
} else if (args->action == CONCURRENT_TASK_ACTION_STAT) {
|
||||
int res;
|
||||
struct stat buf;
|
||||
res = stat(args->filename, &buf);
|
||||
if(res < 0) {
|
||||
args->result = ESP_FAIL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
args->result = ESP_OK;
|
||||
|
||||
close:
|
||||
if(f) {
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
done:
|
||||
xSemaphoreGive(args->done);
|
||||
vTaskDelay(1);
|
||||
vTaskDelete(NULL);
|
||||
}
|
||||
|
||||
|
||||
static void test_littlefs_concurrent_rw(const char* filename_prefix)
|
||||
{
|
||||
#define TASK_SIZE 4096
|
||||
char names[4][64];
|
||||
for (size_t i = 0; i < 4; ++i) {
|
||||
snprintf(names[i], sizeof(names[i]), "%s%d", filename_prefix, i + 1);
|
||||
}
|
||||
|
||||
/************************************************
|
||||
* TESTING CONCURRENT WRITES TO DIFFERENT FILES *
|
||||
************************************************/
|
||||
read_write_test_arg_t args1 = READ_WRITE_TEST_ARG_INIT(names[0], 1);
|
||||
read_write_test_arg_t args2 = READ_WRITE_TEST_ARG_INIT(names[1], 2);
|
||||
printf("writing f1 and f2\n");
|
||||
const int cpuid_0 = 0;
|
||||
const int cpuid_1 = portNUM_PROCESSORS - 1;
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw1", TASK_SIZE, &args1, 3, NULL, cpuid_0);
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw2", TASK_SIZE, &args2, 3, NULL, cpuid_1);
|
||||
|
||||
xSemaphoreTake(args1.done, portMAX_DELAY);
|
||||
printf("f1 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args1.result);
|
||||
xSemaphoreTake(args2.done, portMAX_DELAY);
|
||||
printf("f2 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args2.result);
|
||||
|
||||
args1.action = CONCURRENT_TASK_ACTION_READ;
|
||||
args2.action = CONCURRENT_TASK_ACTION_READ;
|
||||
read_write_test_arg_t args3 = READ_WRITE_TEST_ARG_INIT(names[2], 3);
|
||||
read_write_test_arg_t args4 = READ_WRITE_TEST_ARG_INIT(names[3], 4);
|
||||
|
||||
printf("reading f1 and f2, writing f3 and f4, stating f1 concurrently from 2 cores\n");
|
||||
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw3", TASK_SIZE, &args3, 3, NULL, cpuid_1);
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw4", TASK_SIZE, &args4, 3, NULL, cpuid_0);
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw1", TASK_SIZE, &args1, 3, NULL, cpuid_0);
|
||||
xTaskCreatePinnedToCore(&read_write_task, "rw2", TASK_SIZE, &args2, 3, NULL, cpuid_1);
|
||||
|
||||
#if CONFIG_VFS_SUPPORT_DIR
|
||||
read_write_test_arg_t args5 = READ_WRITE_TEST_ARG_INIT(names[0], 3);
|
||||
args5.action = CONCURRENT_TASK_ACTION_STAT;
|
||||
args5.word_count = 300;
|
||||
read_write_test_arg_t args6 = READ_WRITE_TEST_ARG_INIT(names[0], 3);
|
||||
args6.action = CONCURRENT_TASK_ACTION_STAT;
|
||||
args6.word_count = 300;
|
||||
|
||||
|
||||
xTaskCreatePinnedToCore(&read_write_task, "stat1", TASK_SIZE, &args5, 3, NULL, cpuid_0);
|
||||
xTaskCreatePinnedToCore(&read_write_task, "stat2", TASK_SIZE, &args6, 3, NULL, cpuid_1);
|
||||
#endif
|
||||
|
||||
|
||||
xSemaphoreTake(args1.done, portMAX_DELAY);
|
||||
printf("f1 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args1.result);
|
||||
xSemaphoreTake(args2.done, portMAX_DELAY);
|
||||
printf("f2 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args2.result);
|
||||
xSemaphoreTake(args3.done, portMAX_DELAY);
|
||||
printf("f3 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args3.result);
|
||||
xSemaphoreTake(args4.done, portMAX_DELAY);
|
||||
printf("f4 done\n");
|
||||
|
||||
#if CONFIG_VFS_SUPPORT_DIR
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args5.result);
|
||||
xSemaphoreTake(args5.done, portMAX_DELAY);
|
||||
printf("stat1 done\n");
|
||||
TEST_ASSERT_EQUAL(ESP_OK, args6.result);
|
||||
xSemaphoreTake(args6.done, portMAX_DELAY);
|
||||
printf("stat2 done\n");
|
||||
#endif
|
||||
|
||||
|
||||
vSemaphoreDelete(args1.done);
|
||||
vSemaphoreDelete(args2.done);
|
||||
vSemaphoreDelete(args3.done);
|
||||
vSemaphoreDelete(args4.done);
|
||||
#undef TASK_SIZE
|
||||
}
|
||||
|
||||
#if CONFIG_LITTLEFS_SPIFFS_COMPAT
|
||||
TEST_CASE("SPIFFS COMPAT: file creation and deletion", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
const char* filename = littlefs_base_path "/spiffs_compat/foo/bar/spiffs_compat.bin";
|
||||
|
||||
FILE* f = fopen(filename, "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_TRUE(fputs("bar", f) != EOF);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
TEST_ASSERT_EQUAL(0, unlink(filename));
|
||||
|
||||
/* check to see if all the directories were deleted */
|
||||
struct stat sb;
|
||||
if (test_littlefs_stat(littlefs_base_path "/spiffs_compat", &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
TEST_FAIL_MESSAGE("Empty directories were not deleted");
|
||||
}
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("SPIFFS COMPAT: file creation and rename", "[littlefs]")
|
||||
{
|
||||
test_setup();
|
||||
|
||||
int res;
|
||||
char message[256];
|
||||
const char* src = littlefs_base_path "/spiffs_compat/src/foo/bar/spiffs_compat.bin";
|
||||
const char* dst = littlefs_base_path "/spiffs_compat/dst/foo/bar/spiffs_compat.bin";
|
||||
|
||||
FILE* f = fopen(src, "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_TRUE(fputs("bar", f) != EOF);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
|
||||
res = rename(src, dst);
|
||||
snprintf(message, sizeof(message), "errno: %d", errno);
|
||||
TEST_ASSERT_EQUAL_MESSAGE(0, res, message);
|
||||
|
||||
/* check to see if all the directories were deleted */
|
||||
struct stat sb;
|
||||
if (test_littlefs_stat(littlefs_base_path "/spiffs_compat/src", &sb) == 0 && S_ISDIR(sb.st_mode)) {
|
||||
TEST_FAIL_MESSAGE("Empty directories were not deleted");
|
||||
}
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
#endif // CONFIG_LITTLEFS_SPIFFS_COMPAT
|
||||
|
||||
TEST_CASE("Rewriting file frees space immediately (#7426)", "[littlefs]")
|
||||
{
|
||||
/* modified from:
|
||||
* https://github.com/esp8266/Arduino/commit/c663c55926f205723c3d56dd7030bacbe7960f8e
|
||||
*/
|
||||
|
||||
test_setup();
|
||||
|
||||
size_t total = 0, used = 0;
|
||||
TEST_ESP_OK(esp_littlefs_info(littlefs_test_partition_label, &total, &used));
|
||||
|
||||
// 2 block overhead
|
||||
int kb_to_write = (total - used - (2*4096)) / 1024;
|
||||
|
||||
// Create and overwrite a file >50% of spaceA (48/64K)
|
||||
uint8_t buf[1024];
|
||||
memset(buf, 0xaa, 1024);
|
||||
for (uint8_t x = 0; x < 2; x++) {
|
||||
FILE *f = fopen(littlefs_base_path "/file1.bin", "w");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
|
||||
for (size_t i = 0; i < kb_to_write; i++) {
|
||||
TEST_ASSERT_EQUAL_INT(1024, fwrite(buf, 1, 1024, f));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
TEST_CASE("esp_littlefs_info returns used_bytes > total_bytes", "[littlefs]")
|
||||
{
|
||||
// https://github.com/joltwallet/esp_littlefs/issues/66
|
||||
test_setup();
|
||||
const char foo[] = "foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo";
|
||||
|
||||
char names[7][64];
|
||||
for (size_t i = 0; i < 7; ++i) {
|
||||
snprintf(names[i], sizeof(names[i]), littlefs_base_path "/%d", i + 1);
|
||||
unlink(names[i]); // Make sure these files don't exist
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < 7; ++i) {
|
||||
FILE* f = fopen(names[i], "wb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char val = 'c';
|
||||
size_t n_bytes = 65432;
|
||||
for(int i=0; i < n_bytes; i++) {
|
||||
TEST_ASSERT_EQUAL(1, fwrite(&val, 1, 1, f));
|
||||
}
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
bool disk_full = false;
|
||||
int i = 0;
|
||||
while(!disk_full){
|
||||
char *filename = names[i % 7];
|
||||
FILE* f = fopen(filename, "a+b");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
size_t n_bytes = 200 + i % 17;
|
||||
int amount_written = fwrite(foo, n_bytes, 1, f);
|
||||
if(amount_written != 1) {
|
||||
disk_full = true;
|
||||
}
|
||||
if(0 != fclose(f)){
|
||||
disk_full = true;
|
||||
}
|
||||
|
||||
size_t total = 0, used = 0;
|
||||
TEST_ESP_OK(esp_littlefs_info(littlefs_test_partition_label, &total, &used));
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(used, total);
|
||||
//printf("used: %d total: %d\n", used, total);
|
||||
i++;
|
||||
}
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
#if CONFIG_LITTLEFS_OPEN_DIR
|
||||
TEST_CASE("open with flag O_DIRECTORY", "[littlefs]")
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
struct stat stat;
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
char path[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
test_setup();
|
||||
|
||||
fd = open("/littlefs/dir1/", O_DIRECTORY | O_NOFOLLOW);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/dir1/", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = fstat(fd, &stat);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_NOT_EQUAL(0, stat.st_size);
|
||||
TEST_ASSERT_EQUAL(S_IFDIR, stat.st_mode);
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
fd = open("/littlefs/dir1/dir2/", O_DIRECTORY | O_NOFOLLOW);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/dir1/dir2/", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = fstat(fd, &stat);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_NOT_EQUAL(0, stat.st_size);
|
||||
TEST_ASSERT_EQUAL(S_IFDIR, stat.st_mode);
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
fd = open("/littlefs/dir1/dir2/test.txt", O_CREAT | O_RDWR);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/dir1/dir2/test.txt", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = fstat(fd, &stat);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL(0, stat.st_size);
|
||||
TEST_ASSERT_EQUAL(S_IFREG, stat.st_mode);
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
/* File is created in previous step */
|
||||
fd = open("/littlefs/dir1/dir2/test.txt", O_DIRECTORY | O_NOFOLLOW);
|
||||
TEST_ASSERT_EQUAL(-1, fd);
|
||||
TEST_ASSERT_EQUAL(ENOTDIR, errno);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_CASE("fcntl get flags", "[littlefs]")
|
||||
{
|
||||
int fd;
|
||||
int ret;
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
char path[MAXPATHLEN];
|
||||
#endif
|
||||
|
||||
test_setup();
|
||||
|
||||
fd = open("/littlefs/test.txt", O_CREAT | O_WRONLY);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
ret = fcntl(fd, F_GETFL);
|
||||
TEST_ASSERT_EQUAL(O_WRONLY, ret);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/test.txt", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
fd = open("/littlefs/test.txt", O_RDONLY);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
ret = fcntl(fd, F_GETFL);
|
||||
TEST_ASSERT_EQUAL(O_RDONLY, ret);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/test.txt", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
fd = open("/littlefs/test.txt", O_RDWR);
|
||||
TEST_ASSERT_GREATER_OR_EQUAL_INT(0, fd);
|
||||
ret = fcntl(fd, F_GETFL);
|
||||
TEST_ASSERT_EQUAL(O_RDWR, ret);
|
||||
#if CONFIG_LITTLEFS_FCNTL_GET_PATH
|
||||
ret = fcntl(fd, F_GETPATH, path);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
TEST_ASSERT_EQUAL_STRING("/littlefs/test.txt", path);
|
||||
memset(path, 0, MAXPATHLEN);
|
||||
#endif
|
||||
ret = close(fd);
|
||||
TEST_ASSERT_EQUAL(0, ret);
|
||||
|
||||
test_teardown();
|
||||
}
|
||||
|
||||
/**
|
||||
* Cannot use buitin `stat` since it depends on CONFIG_VFS_SUPPORT_DIR.
|
||||
*/
|
||||
static int test_littlefs_stat(const char *path, struct stat *buf){
|
||||
int res;
|
||||
FILE* f = fopen(path, "r");
|
||||
if(!f){
|
||||
return -1;
|
||||
}
|
||||
int fd = fileno(f);
|
||||
res = fstat(fd, buf);
|
||||
fclose(f);
|
||||
return res;
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "test_littlefs_common.h"
|
||||
|
||||
|
||||
const char littlefs_test_partition_label[] = "flash_test";
|
||||
const char littlefs_test_hello_str[] = "Hello, World!\n";
|
||||
|
||||
|
||||
void test_littlefs_create_file_with_text(const char* name, const char* text)
|
||||
{
|
||||
printf("Writing to \"%s\"\n", name);
|
||||
FILE* f = fopen(name, "wb");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
TEST_ASSERT_TRUE(fputs(text, f) != EOF);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
void test_littlefs_read_file(const char* filename)
|
||||
{
|
||||
FILE* f = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char buf[32] = { 0 };
|
||||
int cb = fread(buf, 1, sizeof(buf), f);
|
||||
TEST_ASSERT_EQUAL(strlen(littlefs_test_hello_str), cb);
|
||||
TEST_ASSERT_EQUAL(0, strcmp(littlefs_test_hello_str, buf));
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
void test_littlefs_read_file_with_content(const char* filename, const char* expected_content)
|
||||
{
|
||||
FILE* f = fopen(filename, "r");
|
||||
TEST_ASSERT_NOT_NULL(f);
|
||||
char buf[32] = { 0 };
|
||||
|
||||
const size_t expected_content_length = strlen(expected_content);
|
||||
size_t read_length = 0;
|
||||
int cb = 0;
|
||||
do {
|
||||
cb = fread(buf, 1, sizeof(buf), f);
|
||||
TEST_ASSERT_TRUE(read_length + cb <= expected_content_length);
|
||||
TEST_ASSERT_TRUE(memcmp(buf, &expected_content[read_length], cb) == 0);
|
||||
read_length += cb;
|
||||
} while(cb != 0);
|
||||
|
||||
TEST_ASSERT_EQUAL(expected_content_length, read_length);
|
||||
TEST_ASSERT_EQUAL(0, fclose(f));
|
||||
}
|
||||
|
||||
void test_setup() {
|
||||
esp_littlefs_format(littlefs_test_partition_label);
|
||||
const esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = littlefs_base_path,
|
||||
.partition_label = littlefs_test_partition_label,
|
||||
.format_if_mount_failed = true
|
||||
};
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
printf("Test setup complete.\n");
|
||||
}
|
||||
|
||||
void test_teardown(){
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister(littlefs_test_partition_label));
|
||||
TEST_ASSERT_TRUE( heap_caps_check_integrity_all(true) );
|
||||
printf("Test teardown complete.\n");
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#ifndef TEST_LITTLEFS_COMMON_H__
|
||||
#define TEST_LITTLEFS_COMMON_H__
|
||||
|
||||
#include "esp_littlefs.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#include "errno.h"
|
||||
#include "esp_err.h"
|
||||
#include "esp_heap_caps.h"
|
||||
#include "esp_idf_version.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_partition.h"
|
||||
#include "esp_rom_sys.h"
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_timer.h"
|
||||
#include "esp_vfs.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "test_utils.h"
|
||||
#include "unity.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/param.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/unistd.h>
|
||||
#include <time.h>
|
||||
|
||||
#define littlefs_base_path "/littlefs"
|
||||
extern const char littlefs_test_partition_label[];
|
||||
extern const char littlefs_test_hello_str[];
|
||||
|
||||
|
||||
void test_littlefs_create_file_with_text(const char* name, const char* text);
|
||||
void test_littlefs_read_file(const char* filename);
|
||||
void test_littlefs_read_file_with_content(const char* filename, const char* expected_content);
|
||||
|
||||
void test_setup();
|
||||
void test_teardown();
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,162 @@
|
||||
// #define LOG_LOCAL_LEVEL 4
|
||||
#include "test_littlefs_common.h"
|
||||
#include "spi_flash_mmap.h"
|
||||
#include "esp_flash.h"
|
||||
|
||||
static esp_partition_t get_test_data_static_partition(void);
|
||||
static void test_setup_static(const esp_partition_t* partition);
|
||||
static void test_teardown_static(const esp_partition_t* partition);
|
||||
|
||||
void test_setup_static(const esp_partition_t* partition)
|
||||
{
|
||||
const esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = littlefs_base_path,
|
||||
.partition_label = NULL,
|
||||
.partition = partition,
|
||||
.dont_mount = false,
|
||||
.read_only = true,
|
||||
};
|
||||
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
TEST_ASSERT_TRUE(heap_caps_check_integrity_all(true));
|
||||
TEST_ASSERT_TRUE(esp_littlefs_partition_mounted(partition));
|
||||
printf("Test setup complete.\n");
|
||||
}
|
||||
|
||||
void test_teardown_static(const esp_partition_t* partition)
|
||||
{
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister_partition(partition));
|
||||
TEST_ASSERT_TRUE(heap_caps_check_integrity_all(true));
|
||||
TEST_ASSERT_FALSE(esp_littlefs_partition_mounted(partition));
|
||||
printf("Test teardown complete.\n");
|
||||
}
|
||||
|
||||
esp_partition_t get_test_data_static_partition(void)
|
||||
{
|
||||
/* This finds the static partition embedded in the firmware and constructs a partition struct */
|
||||
extern const uint8_t partition_blob_start[] asm("_binary_testfs_bin_start");
|
||||
extern const uint8_t partition_blob_end[] asm("_binary_testfs_bin_end");
|
||||
|
||||
return (esp_partition_t){
|
||||
.flash_chip = esp_flash_default_chip,
|
||||
.type = ESP_PARTITION_TYPE_DATA,
|
||||
.subtype = ESP_PARTITION_SUBTYPE_DATA_FAT,
|
||||
.address = spi_flash_cache2phys(partition_blob_start),
|
||||
.size = ((uint32_t)partition_blob_end) - ((uint32_t)partition_blob_start),
|
||||
.label = "",
|
||||
.encrypted = false,
|
||||
};
|
||||
}
|
||||
|
||||
TEST_CASE("can read partition", "[littlefs_static]")
|
||||
{
|
||||
const esp_partition_t partition = get_test_data_static_partition();
|
||||
test_setup_static(&partition);
|
||||
size_t total = 0, used = 0;
|
||||
TEST_ESP_OK(esp_littlefs_partition_info(&partition, &total, &used));
|
||||
printf("total: %d, used: %d\n", total, used);
|
||||
TEST_ASSERT_EQUAL(20480, used); // The test FS has 5 used blocks of 4K
|
||||
test_teardown_static(&partition);
|
||||
}
|
||||
|
||||
TEST_CASE("can read file", "[littlefs_static]")
|
||||
{
|
||||
const esp_partition_t partition = get_test_data_static_partition();
|
||||
test_setup_static(&partition);
|
||||
|
||||
test_littlefs_read_file_with_content(littlefs_base_path "/test1.txt", "test1");
|
||||
test_littlefs_read_file_with_content(littlefs_base_path "/test2.txt", "test2");
|
||||
test_littlefs_read_file_with_content(littlefs_base_path "/pangram.txt", "The quick brown fox jumps over the lazy dog");
|
||||
test_littlefs_read_file_with_content(
|
||||
littlefs_base_path "/test_folder/lorem_ipsum.txt",
|
||||
"Lorem ipsum dolor sit amet, consectetuer adipiscing elit, sed diam nonummy nibh euismod tincidunt ut laoreet "
|
||||
"dolore magna aliquam erat volutpat. Ut wisi enim ad minim veniam, quis nostrud exerci tation ullamcorper suscipit "
|
||||
"lobortis nisl ut aliquip ex ea commodo consequat. Duis autem vel eum iriure dolor in hendrerit in vulputate velit "
|
||||
"esse molestie consequat, vel illum dolore eu feugiat nulla facilisis at vero eros et accumsan et iusto odio "
|
||||
"dignissim qui blandit praesent luptatum zzril delenit augue duis dolore te feugait nulla facilisi. Nam liber "
|
||||
"tempor cum soluta nobis eleifend option congue nihil imperdiet doming id quod mazim placerat facer possim assum. "
|
||||
"Typi non habent claritatem insitam; est usus legentis in iis qui facit eorum claritatem. Investigationes "
|
||||
"demonstraverunt lectores legere me lius quod ii legunt saepius. Claritas est etiam processus dynamicus, qui "
|
||||
"sequitur mutationem consuetudium lectorum. Mirum est notare quam littera gothica, quam nunc putamus parum claram, "
|
||||
"anteposuerit litterarum formas humanitatis per seacula quarta decima et quinta decima. Eodem modo typi, qui nunc "
|
||||
"nobis videntur parum clari, fiant sollemnes in futurum.");
|
||||
|
||||
test_teardown_static(&partition);
|
||||
}
|
||||
|
||||
TEST_CASE("can't create file", "[littlefs_static]")
|
||||
{
|
||||
const esp_partition_t partition = get_test_data_static_partition();
|
||||
test_setup_static(&partition);
|
||||
|
||||
FILE* f = fopen(littlefs_base_path "/new_file.txt", "wb");
|
||||
TEST_ASSERT_NULL(f);
|
||||
test_teardown_static(&partition);
|
||||
}
|
||||
|
||||
TEST_CASE("can't delete file", "[littlefs_static]")
|
||||
{
|
||||
const esp_partition_t partition = get_test_data_static_partition();
|
||||
test_setup_static(&partition);
|
||||
|
||||
TEST_ASSERT_EQUAL(unlink(littlefs_base_path "/test1.txt"), -1);
|
||||
test_littlefs_read_file_with_content(littlefs_base_path "/test1.txt", "test1");
|
||||
|
||||
test_teardown_static(&partition);
|
||||
}
|
||||
|
||||
TEST_CASE("can't write to file", "[littlefs_static]")
|
||||
{
|
||||
const esp_partition_t partition = get_test_data_static_partition();
|
||||
test_setup_static(&partition);
|
||||
|
||||
FILE* f = fopen(littlefs_base_path "/test1.txt", "wb");
|
||||
TEST_ASSERT_NULL(f);
|
||||
test_littlefs_read_file_with_content(littlefs_base_path "/test1.txt", "test1");
|
||||
|
||||
test_teardown_static(&partition);
|
||||
}
|
||||
|
||||
TEST_CASE("grow filesystem", "[littlefs]")
|
||||
{
|
||||
esp_partition_t partition;
|
||||
const esp_partition_t *partition_ro = esp_partition_find_first(
|
||||
ESP_PARTITION_TYPE_DATA,
|
||||
ESP_PARTITION_SUBTYPE_ANY,
|
||||
littlefs_test_partition_label
|
||||
);
|
||||
|
||||
esp_vfs_littlefs_conf_t conf = {
|
||||
.base_path = littlefs_base_path,
|
||||
.partition = (const esp_partition_t *) &partition,
|
||||
};
|
||||
|
||||
size_t shrink_bytes;
|
||||
|
||||
/* Format a smaller partition */
|
||||
{
|
||||
memcpy(&partition, partition_ro, sizeof(esp_partition_t));
|
||||
// Shrink the partition by 2 blocks
|
||||
partition.size -= 8192;
|
||||
TEST_ESP_OK(esp_littlefs_format_partition(&partition));
|
||||
partition.size += 8192;
|
||||
}
|
||||
|
||||
/* Mount, ensure that it does NOT grow */
|
||||
{
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
TEST_ESP_OK(esp_littlefs_partition_info(&partition, &shrink_bytes, NULL));
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister_partition(&partition));
|
||||
TEST_ASSERT_EQUAL(partition.size - 8192, shrink_bytes);
|
||||
}
|
||||
|
||||
/* Mount, ensure that it DOES grow */
|
||||
{
|
||||
size_t grow_bytes;
|
||||
conf.grow_on_mount = true;
|
||||
TEST_ESP_OK(esp_vfs_littlefs_register(&conf));
|
||||
TEST_ESP_OK(esp_littlefs_partition_info(&partition, &grow_bytes, NULL));
|
||||
TEST_ESP_OK(esp_vfs_littlefs_unregister_partition(&partition));
|
||||
TEST_ASSERT_EQUAL(shrink_bytes + 8192, grow_bytes);
|
||||
}
|
||||
}
|
||||
BIN
managed_components/joltwallet__littlefs/test/testfs.bin
Normal file
BIN
managed_components/joltwallet__littlefs/test/testfs.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user