/* * Copyright (C) 2017 HAW-Hamburg * * This file is subject to the terms and conditions of the GNU Lesser * General Public License v2.1. See the file LICENSE in the top level * directory for more details. */ /** * @ingroup tests * @{ * * @file * @brief test application for using fatfs with vfs * * @author Michel Rottleuthner * @} */ #include #include #include #include #include "fs/fatfs.h" #include "vfs.h" #include "mtd.h" #include "board.h" #include "kernel_defines.h" #ifdef MODULE_MTD_SDCARD #include "mtd_sdcard.h" #include "sdcard_spi.h" #include "sdcard_spi_params.h" #endif #if FATFS_FFCONF_OPT_FS_NORTC == 0 #include "periph/rtc.h" #endif #define MNT_PATH "/test" #define FNAME1 "TEST.TXT" #define FNAME2 "NEWFILE.TXT" #define FNAME_RNMD "RENAMED.TXT" #define FNAME_NXIST "NOFILE.TXT" #define FULL_FNAME1 (MNT_PATH "/" FNAME1) #define FULL_FNAME2 (MNT_PATH "/" FNAME2) #define FULL_FNAME_RNMD (MNT_PATH "/" FNAME_RNMD) #define FULL_FNAME_NXIST (MNT_PATH "/" FNAME_NXIST) #define DIR_NAME "SOMEDIR" static const char test_txt[] = "the test file content 123 abc"; static const char test_txt2[] = "another text"; static const char test_txt3[] = "hello world for vfs"; static fatfs_desc_t fatfs; static vfs_mount_t _test_vfs_mount = { .mount_point = MNT_PATH, .fs = &fatfs_file_system, .private_data = (void *)&fatfs, }; #if defined(MODULE_MTD_NATIVE) || defined(MODULE_MTD_MCI) /* mtd devices are provided in the board's board_init.c*/ extern mtd_dev_t *mtd0; #endif #if defined(MODULE_MTD_SDCARD) #define SDCARD_SPI_NUM ARRAY_SIZE(sdcard_spi_params) extern sdcard_spi_t sdcard_spi_devs[SDCARD_SPI_NUM]; mtd_sdcard_t mtd_sdcard_devs[SDCARD_SPI_NUM]; /* always default to first sdcard*/ static mtd_dev_t *mtd_sdcard = (mtd_dev_t*)&mtd_sdcard_devs[0]; #endif static void print_test_result(const char *test_name, int ok) { printf("%s:[%s]\n", test_name, ok ? "OK" : "FAILED"); } static void test_format(void) { #ifdef MODULE_FATFS_VFS_FORMAT print_test_result("test_format__format", vfs_format(&_test_vfs_mount) == 0); #endif } static void test_mount(void) { print_test_result("test_mount__mount", vfs_mount(&_test_vfs_mount) == 0); print_test_result("test_mount__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_open(void) { int fd; print_test_result("test_open__mount", vfs_mount(&_test_vfs_mount) == 0); /* try to open file that doesn't exist */ fd = vfs_open(FULL_FNAME_NXIST, O_RDONLY, 0); print_test_result("test_open__open", fd == -ENOENT); /* open file with RO, WO and RW access */ fd = vfs_open(FULL_FNAME1, O_RDONLY, 0); print_test_result("test_open__open_ro", fd >= 0); print_test_result("test_open__close_ro", vfs_close(fd) == 0); fd = vfs_open(FULL_FNAME1, O_WRONLY, 0); print_test_result("test_open__open_wo", fd >= 0); print_test_result("test_open__close_wo", vfs_close(fd) == 0); fd = vfs_open(FULL_FNAME1, O_RDWR, 0); print_test_result("test_open__open_rw", fd >= 0); print_test_result("test_open__close_rw", vfs_close(fd) == 0); print_test_result("test_open__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_rw(void) { char buf[sizeof(test_txt) + sizeof(test_txt2)]; int fd; ssize_t nr, nw; off_t new_pos; print_test_result("test_rw__mount", vfs_mount(&_test_vfs_mount) == 0); fd = vfs_open(FULL_FNAME1, O_RDONLY, 0); print_test_result("test_rw__open_ro", fd >= 0); /* compare file content with expected value */ memset(buf, 0, sizeof(buf)); nr = vfs_read(fd, buf, sizeof(test_txt)); print_test_result("test_rw__read_ro", (nr == sizeof(test_txt)) && (strncmp(buf, test_txt, sizeof(test_txt)) == 0)); /* try to write to RO file (success if no bytes are actually written) */ nw = vfs_write(fd, test_txt2, sizeof(test_txt2)); print_test_result("test_rw__write_ro", nw <= 0); print_test_result("test_rw__close_ro", vfs_close(fd) == 0); fd = vfs_open("/test/test.txt", O_WRONLY, 0); print_test_result("test_rw__open_wo", fd >= 0); /* try to read from WO file (success if no bytes are actually read) */ nr = vfs_read(fd, buf, sizeof(test_txt)); print_test_result("test_rw__read_wo", nr <= 0); print_test_result("test_rw__close_wo", vfs_close(fd) == 0); memset(buf, 0, sizeof(buf)); fd = vfs_open(FULL_FNAME1, O_RDWR, 0); print_test_result("test_rw__open_rw", fd >= 0); /* read file content and compare it to the expected value */ nr = vfs_read(fd, buf, sizeof(test_txt)); print_test_result("test_rw__read_rw", (nr == sizeof(test_txt)) && (strncmp(buf, test_txt, sizeof(test_txt)) == 0)); /* write to the file (text should be appended to the end of file) */ nw = vfs_write(fd, test_txt2, sizeof(test_txt2)); print_test_result("test_rw__write_rw", nw == sizeof(test_txt2)); /* seek to start of file */ new_pos = vfs_lseek(fd, 0, SEEK_SET); print_test_result("test_rw__lseek", new_pos == 0); /* read file content and compare to expected value */ memset(buf, 0, sizeof(buf)); nr = vfs_read(fd, buf, sizeof(buf)); print_test_result("test_rw__read_rw", (nr == sizeof(buf)) && (strncmp(buf, test_txt, sizeof(test_txt)) == 0) && (strncmp(&buf[sizeof(test_txt)], test_txt2, sizeof(test_txt2)) == 0)); print_test_result("test_rw__close_rw", vfs_close(fd) == 0); /* create new file */ fd = vfs_open(FULL_FNAME2, O_RDWR | O_CREAT, 0); print_test_result("test_rw__open_rwc", fd >= 0); /* write to the new file, read it's content and compare to expected value */ nw = vfs_write(fd, test_txt3, sizeof(test_txt3)); print_test_result("test_rw__write_rwc", nw == sizeof(test_txt3)); new_pos = vfs_lseek(fd, 0, SEEK_SET); print_test_result("test_rw__lseek_rwc", new_pos == 0); memset(buf, 0, sizeof(buf)); nr = vfs_read(fd, buf, sizeof(test_txt3)); print_test_result("test_rw__read_rwc", (nr == sizeof(test_txt3)) && (strncmp(buf, test_txt3, sizeof(test_txt3)) == 0)); print_test_result("test_rw__close_rwc", vfs_close(fd) == 0); print_test_result("test_rw__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_dir(void) { vfs_DIR dir; vfs_dirent_t entry; vfs_dirent_t entry2; print_test_result("test_dir__mount", vfs_mount(&_test_vfs_mount) == 0); print_test_result("test_dir__opendir", vfs_opendir(&dir, MNT_PATH) == 0); print_test_result("test_dir__readdir1", vfs_readdir(&dir, &entry) == 1); print_test_result("test_dir__readdir2", vfs_readdir(&dir, &entry2) == 1); print_test_result("test_dir__readdir_name", ((strncmp(FNAME1, entry.d_name, sizeof(FNAME1)) == 0) && (strncmp(FNAME2, entry2.d_name, sizeof(FNAME2)) == 0)) || ((strncmp(FNAME1, entry2.d_name, sizeof(FNAME1)) == 0) && (strncmp(FNAME2, entry.d_name, sizeof(FNAME2)) == 0))); print_test_result("test_dir__readdir3", vfs_readdir(&dir, &entry2) == 0); print_test_result("test_dir__closedir", vfs_closedir(&dir) == 0); print_test_result("test_dir__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_rename(void) { vfs_DIR dir; vfs_dirent_t entry; vfs_dirent_t entry2; print_test_result("test_rename__mount", vfs_mount(&_test_vfs_mount) == 0); print_test_result("test_rename__rename", vfs_rename(FULL_FNAME1, FULL_FNAME_RNMD) == 0); print_test_result("test_rename__opendir", vfs_opendir(&dir, MNT_PATH) == 0); print_test_result("test_rename__readdir1", vfs_readdir(&dir, &entry) == 1); print_test_result("test_rename__readdir2", vfs_readdir(&dir, &entry2) == 1); print_test_result("test_rename__check_name", ((strncmp(FNAME_RNMD, entry.d_name, sizeof(FNAME_RNMD)) == 0) && (strncmp(FNAME2, entry2.d_name, sizeof(FNAME2)) == 0)) || ((strncmp(FNAME_RNMD, entry2.d_name, sizeof(FNAME_RNMD)) == 0) && (strncmp(FNAME2, entry.d_name, sizeof(FNAME2)) == 0))); print_test_result("test_rename__readdir3", vfs_readdir(&dir, &entry2) == 0); print_test_result("test_rename__closedir", vfs_closedir(&dir) == 0); print_test_result("test_rename__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_unlink(void) { vfs_DIR dir; vfs_dirent_t entry; print_test_result("test_unlink__mount", vfs_mount(&_test_vfs_mount) == 0); print_test_result("test_unlink__unlink1", vfs_unlink(FULL_FNAME2) == 0); print_test_result("test_unlink__unlink2", vfs_unlink(FULL_FNAME_RNMD) == 0); print_test_result("test_unlink__opendir", vfs_opendir(&dir, MNT_PATH) == 0); print_test_result("test_unlink__readdir", vfs_readdir(&dir, &entry) == 0); print_test_result("test_unlink__closedir", vfs_closedir(&dir) == 0); print_test_result("test_unlink__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_mkrmdir(void) { vfs_DIR dir; print_test_result("test_mkrmdir__mount", vfs_mount(&_test_vfs_mount) == 0); print_test_result("test_mkrmdir__mkdir", vfs_mkdir(MNT_PATH"/"DIR_NAME, 0) == 0); print_test_result("test_mkrmdir__opendir1", vfs_opendir(&dir, MNT_PATH"/"DIR_NAME) == 0); print_test_result("test_mkrmdir__closedir", vfs_closedir(&dir) == 0); print_test_result("test_mkrmdir__rmdir", vfs_rmdir(MNT_PATH"/"DIR_NAME) == 0); print_test_result("test_mkrmdir__opendir2", vfs_opendir(&dir, MNT_PATH"/"DIR_NAME) < 0); print_test_result("test_mkrmdir__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_create(void) { int fd; ssize_t nw; print_test_result("test_create__mount", vfs_mount(&_test_vfs_mount) == 0); fd = vfs_open(FULL_FNAME1, O_WRONLY | O_CREAT, 0); print_test_result("test_create__open_wo", fd >= 0); nw = vfs_write(fd, test_txt, sizeof(test_txt)); print_test_result("test_create__write_wo", nw == sizeof(test_txt)); print_test_result("test_create__close_wo", vfs_close(fd) == 0); /* test create if file exists */ fd = vfs_open(FULL_FNAME1, O_WRONLY | O_CREAT, 0); print_test_result("test_create__open_wo2", fd >= 0); nw = vfs_write(fd, test_txt, sizeof(test_txt)); print_test_result("test_create__write_wo2", nw == sizeof(test_txt)); print_test_result("test_create__close_wo2", vfs_close(fd) == 0); print_test_result("test_create__umount", vfs_umount(&_test_vfs_mount, false) == 0); } static void test_fstat(void) { int fd; struct stat stat_buf; print_test_result("test_stat__mount", vfs_mount(&_test_vfs_mount) == 0); fd = vfs_open(FULL_FNAME1, O_WRONLY | O_TRUNC, 0); print_test_result("test_stat__open", fd >= 0); print_test_result("test_stat__write", vfs_write(fd, test_txt, sizeof(test_txt)) == sizeof(test_txt)); print_test_result("test_stat__close", vfs_close(fd) == 0); print_test_result("test_stat__direct", vfs_stat(FULL_FNAME1, &stat_buf) == 0); fd = vfs_open(FULL_FNAME1, O_RDONLY, 0); print_test_result("test_stat__open", fd >= 0); print_test_result("test_stat__stat", vfs_fstat(fd, &stat_buf) == 0); print_test_result("test_stat__close", vfs_close(fd) == 0); print_test_result("test_stat__size", stat_buf.st_size == sizeof(test_txt)); print_test_result("test_stat__umount", vfs_umount(&_test_vfs_mount, false) == 0); } #if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) static void test_libc(void) { FILE* fl; char buf[sizeof(test_txt) + sizeof(test_txt2)]; print_test_result("test_libc__mount", vfs_mount(&_test_vfs_mount) == 0); /* try to open file that doesn't exist */ fl = fopen(FULL_FNAME_NXIST, "r"); print_test_result("test_libc__fopen", fl == NULL); if (fl) { fclose(fl); } /* create new file write and check content */ remove(FULL_FNAME2); fl = fopen(FULL_FNAME2, "w+"); print_test_result("test_libc__fopen_w", fl != NULL); if (fl) { print_test_result("test_libc__fputs_w", fputs(test_txt, fl) >= 0); rewind(fl); print_test_result("test_libc__fread_w", fread(buf, sizeof(*buf), sizeof(buf), fl) > 0); print_test_result("test_libc__strcmp_w", strcmp(test_txt, buf) == 0); print_test_result("test_libc__fclose_w", fclose(fl) == 0); } /* cppcheck-suppress resourceLeak * (reason: cppcheck <2.0 reports a false positive here) */ fl = fopen(FULL_FNAME2, "r"); /* open file RO */ print_test_result("test_libc__fopen_r", fl != NULL); if (fl) { print_test_result("test_libc__fclose_r", fclose(fl) == 0); } /* remove file */ print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0); /* append to non existing file */ fl = fopen(FULL_FNAME2, "a"); print_test_result("test_libc__fopen_a", fl != NULL); if (fl) { print_test_result("test_libc__fputs_a", fputs(test_txt, fl) >= 0); print_test_result("test_libc__fclose_a", fclose(fl) == 0); } /* append to existing file and check content */ fl = fopen(FULL_FNAME2, "a+"); print_test_result("test_libc__fopen_a2", fl != NULL); if (fl) { print_test_result("test_libc__fputs_a2", fputs(test_txt2, fl) >= 0); rewind(fl); print_test_result("test_libc__fread_a2", fread(buf, sizeof(*buf), sizeof(buf), fl) > 0); print_test_result("test_libc__strcmp_a2", strncmp(test_txt, buf, strlen(test_txt)) == 0); print_test_result("test_libc__strcmp_a2", strncmp(test_txt2, &buf[strlen(test_txt)], strlen(test_txt2)) == 0); print_test_result("test_libc__fclose_a2", fclose(fl) == 0); } print_test_result("test_libc__remove", remove(FULL_FNAME2) == 0); print_test_result("test_libc__umount", vfs_umount(&_test_vfs_mount, false) == 0); } #endif int main(void) { #if MODULE_MTD_SDCARD for(unsigned int i = 0; i < SDCARD_SPI_NUM; i++){ mtd_sdcard_devs[i].base.driver = &mtd_sdcard_driver; mtd_sdcard_devs[i].sd_card = &sdcard_spi_devs[i]; mtd_sdcard_devs[i].params = &sdcard_spi_params[i]; mtd_init(&mtd_sdcard_devs[i].base); } #endif #if defined(MODULE_MTD_NATIVE) || defined(MODULE_MTD_MCI) fatfs.dev = mtd0; #endif #if defined(MODULE_MTD_SDCARD) fatfs.dev = mtd_sdcard; #endif printf("Tests for FatFs over VFS - test results will be printed " "in the format test_name:result\n"); test_format(); test_mount(); test_open(); test_rw(); test_dir(); test_rename(); test_unlink(); test_mkrmdir(); test_create(); test_fstat(); #if defined(MODULE_NEWLIB) || defined(MODULE_PICOLIBC) test_libc(); #endif printf("Test end.\n"); return 0; }