mirror of
				https://github.com/esp8266/Arduino.git
				synced 2025-11-03 14:33:37 +03:00 
			
		
		
		
	
		
			
				
	
	
		
			440 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			440 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
static void createFile (const char* name, const char* content)
 | 
						|
{
 | 
						|
    auto f = FSTYPE.open(name, "w");
 | 
						|
    REQUIRE(f);
 | 
						|
    if (content) {
 | 
						|
        f.print(content);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
static String readFile (const char* name)
 | 
						|
{
 | 
						|
    auto f = FSTYPE.open(name, "r");
 | 
						|
    if (f) {
 | 
						|
        return f.readString();
 | 
						|
    }
 | 
						|
    return String();
 | 
						|
}
 | 
						|
 | 
						|
static std::set<String> listDir (const char* path)
 | 
						|
{
 | 
						|
    std::set<String> result;
 | 
						|
    Dir dir = FSTYPE.openDir(path);
 | 
						|
    while (dir.next()) {
 | 
						|
        REQUIRE(result.find(dir.fileName()) == std::end(result));
 | 
						|
        result.insert(dir.fileName());
 | 
						|
    }
 | 
						|
    return result;
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "FS can begin",TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "FS can't begin with zero size",TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(0, 8, 512, "");
 | 
						|
    REQUIRE_FALSE(FSTYPE.begin());
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Before begin is called, open will fail",TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE_FALSE(FSTYPE.open("/foo", "w"));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "FS can create file",TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/test", "");
 | 
						|
    REQUIRE(FSTYPE.exists("/test"));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Files can be written and appended to",TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    {
 | 
						|
        File f = FSTYPE.open("config1.txt", "w");
 | 
						|
        REQUIRE(f);
 | 
						|
        f.println("file 1");
 | 
						|
    }
 | 
						|
    {
 | 
						|
        File f = FSTYPE.open("config1.txt", "a");
 | 
						|
        REQUIRE(f);
 | 
						|
        f.println("file 1 again");
 | 
						|
    }
 | 
						|
    {
 | 
						|
        File f = FSTYPE.open("config1.txt", "r");
 | 
						|
        REQUIRE(f);
 | 
						|
        char buf[128];
 | 
						|
        size_t len = f.read((uint8_t*)buf, sizeof(buf));
 | 
						|
        buf[len] = 0;
 | 
						|
        REQUIRE(strcmp(buf, "file 1\r\nfile 1 again\r\n") == 0);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Files persist after reset", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("config1.txt", "file 1");
 | 
						|
 | 
						|
    FS_MOCK_RESET();
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    REQUIRE(readFile("config1.txt") == "file 1");
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Filesystem is empty after format", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.format());
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/1", "first");
 | 
						|
    createFile("/2", "second");
 | 
						|
    FSTYPE.end();
 | 
						|
    REQUIRE(FSTYPE.format());
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    Dir root = FSTYPE.openDir("/");
 | 
						|
    size_t count = 0;
 | 
						|
    while (root.next()) {
 | 
						|
        ++count;
 | 
						|
    }
 | 
						|
    REQUIRE(count == 0);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "File names which are too long are rejected", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    const char* emptyName = "";
 | 
						|
    const char* longName_31 = "/234567890123456789012345678901";
 | 
						|
    const char* longName_32 = TOOLONGFILENAME;
 | 
						|
    REQUIRE_FALSE(FSTYPE.open(emptyName, "w"));
 | 
						|
    REQUIRE_FALSE(FSTYPE.open(emptyName, "r"));
 | 
						|
    REQUIRE_FALSE(FSTYPE.exists(emptyName));
 | 
						|
    REQUIRE_FALSE(FSTYPE.open(longName_32, "w"));
 | 
						|
    REQUIRE_FALSE(FSTYPE.open(longName_32, "r"));
 | 
						|
    REQUIRE_FALSE(FSTYPE.exists(longName_32));
 | 
						|
    REQUIRE(FSTYPE.open(longName_31, "w"));
 | 
						|
    REQUIRE(FSTYPE.open(longName_31, "r"));
 | 
						|
    REQUIRE(FSTYPE.exists(longName_31));
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "#1685 Duplicate files", "[fs][bugreport]")
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/config", "some text");
 | 
						|
    createFile("/data", "");
 | 
						|
    readFile("/config");
 | 
						|
    createFile("/data", "more text");
 | 
						|
    auto files = listDir("/");
 | 
						|
    REQUIRE(files.size() == 2);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "#1819 Can list all files with openDir(\"\")", "[fs][bugreport]")
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(96, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/file1", "some text");
 | 
						|
    createFile("/file2", "other text");
 | 
						|
    createFile("file3", "more text");
 | 
						|
    createFile("sorta-dir/file4", "\n");
 | 
						|
    auto files = listDir("");
 | 
						|
    REQUIRE(files.size() == 4);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "truncate", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/file1", "some text");
 | 
						|
    auto f = FSTYPE.open("/file1", "r+");
 | 
						|
    REQUIRE(f.truncate(4));
 | 
						|
    f.close();
 | 
						|
    String s = readFile("/file1");
 | 
						|
    REQUIRE( s == "some" );
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "open(w+) truncates file", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/file1", "some text");
 | 
						|
    String s = readFile("/file1");
 | 
						|
    REQUIRE( s == "some text");
 | 
						|
    auto f = FSTYPE.open("/file1", "w+");
 | 
						|
    f.close();
 | 
						|
    String t = readFile("/file1");
 | 
						|
    REQUIRE( t == "");
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "peek() returns -1 on EOF", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/file1", "some text");
 | 
						|
    auto f = FSTYPE.open("/file1", "r+");
 | 
						|
    REQUIRE(f.seek(8));
 | 
						|
    REQUIRE(f.peek() == 't');
 | 
						|
    REQUIRE(f.read() == 't');
 | 
						|
    REQUIRE(f.peek() == -1);
 | 
						|
    REQUIRE(f.read() == -1);
 | 
						|
    f.close();
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "seek() past EOF returns error (#7323)", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/file1", "some text");
 | 
						|
    auto f = FSTYPE.open("/file1", "r+");
 | 
						|
    REQUIRE_FALSE(f.seek(10));
 | 
						|
    f.close();
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Rewriting file frees space immediately (#7426)", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    FSInfo inf;
 | 
						|
    FSTYPE.info(inf);
 | 
						|
    // Calculate the size to write per-FS, due to differing overheads
 | 
						|
    int kbToWrite = (inf.totalBytes - inf.usedBytes - 8192) / 1024;
 | 
						|
    // Create and overwrite a file >50% of spaceA (48/64K)
 | 
						|
    for (auto x = 0; x < 2; x++) {
 | 
						|
        auto f = FSTYPE.open("/file1.bin", "w");
 | 
						|
        REQUIRE(f);
 | 
						|
        uint8_t buff[1024];
 | 
						|
        memset(buff, 0xaa, 1024);
 | 
						|
        for (auto i = 0; i < kbToWrite; i++) {
 | 
						|
            REQUIRE(f.write(buff, 1024));
 | 
						|
        }
 | 
						|
        f.close();
 | 
						|
        FSTYPE.info(inf);
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
#if FSTYPE != SPIFFS
 | 
						|
 | 
						|
// Timestamp setter (#7682, #7775)
 | 
						|
static time_t _my_time(void)
 | 
						|
{
 | 
						|
    struct tm t;
 | 
						|
    bzero(&t, sizeof(t));
 | 
						|
    t.tm_year = 120;
 | 
						|
    t.tm_mon  = 9;
 | 
						|
    t.tm_mday = 22;
 | 
						|
    t.tm_hour = 12;
 | 
						|
    t.tm_min  = 13;
 | 
						|
    t.tm_sec  = 14;
 | 
						|
    return mktime(&t);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE("Verify timeCallback works properly")
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
 | 
						|
    FSTYPE.setTimeCallback(_my_time);
 | 
						|
    File f = FSTYPE.open("/file.txt", "w");
 | 
						|
    f.write("Had we but world enough, and time,");
 | 
						|
    f.close();
 | 
						|
    time_t expected = _my_time();
 | 
						|
    f = FSTYPE.open("/file.txt", "r");
 | 
						|
    REQUIRE(abs(f.getCreationTime() - expected) < 60);  // FAT has less precision in timestamp than time_t
 | 
						|
    REQUIRE(abs(f.getLastWrite() - expected) < 60);  // FAT has less precision in timestamp than time_t
 | 
						|
    f.close();
 | 
						|
}
 | 
						|
 | 
						|
#endif
 | 
						|
 | 
						|
#ifdef FS_HAS_DIRS
 | 
						|
 | 
						|
#if FSTYPE != SDFS
 | 
						|
// We silently make subdirectories if they do not exist and silently remove
 | 
						|
// them when they're no longer needed, so make sure we can clean up after
 | 
						|
// ourselves.  At some point we may drop this and go to normal POSIX mkdir
 | 
						|
// behavior and expose the FS::mkdir() method, but for now this works OK.
 | 
						|
TEST_CASE(TESTPRE "Removing all files in a subdir removes that subdir", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(128, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/empty", "");
 | 
						|
    createFile("/not_empty", "some text");
 | 
						|
    createFile("/another", "more text");
 | 
						|
    createFile("/subdir/empty", "");
 | 
						|
    createFile("/subdir/not_empty", "text again");
 | 
						|
    auto files = listDir("/");
 | 
						|
    REQUIRE(files.size() == 4);
 | 
						|
    files = listDir("/subdir");
 | 
						|
    REQUIRE(files.size() == 2);
 | 
						|
    // Delete one of subdir, should still exist afterwards
 | 
						|
    FSTYPE.remove("subdir/empty");
 | 
						|
    files = listDir("/subdir");
 | 
						|
    REQUIRE(files.size() == 1);
 | 
						|
    FSTYPE.remove("subdir/not_empty");
 | 
						|
    files = listDir("/subdir");
 | 
						|
    REQUIRE(files.size() == 0);
 | 
						|
    files = listDir("/");
 | 
						|
    REQUIRE(files.size() == 3);
 | 
						|
    REQUIRE(files.find("subdir") == std::end(files));
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
// LittleFS openDir is slightly different than SPIFFS.  In SPIFFS there
 | 
						|
// are no directories and "/" is just another character, so "/a/b/c" is a
 | 
						|
// file in the root dir whose name is "/a/b/c".  In LittleFS we have full
 | 
						|
// directory support, so "/a/b/c" is a file "c" in the "/a/b" dir.
 | 
						|
// This means that if you iterate over dirOpen("/") on SPIFFS you get
 | 
						|
// a list of every file, including "subdirs".  On LittleFS, you need to
 | 
						|
// explicitly open the subdir to see its files.  This behavior is the
 | 
						|
// same as POSIX readdir(), and helps isolate subdirs from each other.
 | 
						|
// Also note that the returned filenames in the "dir.next()" operator
 | 
						|
// will be in that subdir (i.e. if you opendir("/a/b"); f=dir.next();"
 | 
						|
// f.name == "c" and not "/a/b/c" as you would see in SPIFFS.
 | 
						|
TEST_CASE(TESTPRE "Dir lists all files", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/empty", "");
 | 
						|
    createFile("/not_empty", "some text");
 | 
						|
    createFile("/another", "more text");
 | 
						|
    createFile("/subdir/empty", "");
 | 
						|
    createFile("/subdir/not_empty", "text again");
 | 
						|
    auto files = listDir("/");
 | 
						|
    REQUIRE(files.size() == 4);
 | 
						|
    bool empty = (files.find("/empty") != std::end(files)) || (files.find("empty") != std::end(files));
 | 
						|
    REQUIRE(empty);
 | 
						|
    bool not_empty = (files.find("/not_empty") != std::end(files)) || (files.find("not_empty") != std::end(files));
 | 
						|
    REQUIRE(not_empty);
 | 
						|
    bool another = (files.find("/another") != std::end(files)) ||  (files.find("another") != std::end(files));
 | 
						|
    REQUIRE(another);
 | 
						|
 | 
						|
    files = listDir("/subdir");
 | 
						|
    REQUIRE(files.size() == 2);
 | 
						|
    bool sub_empty = (files.find("/empty") != std::end(files)) || (files.find("empty") != std::end(files));
 | 
						|
    REQUIRE(sub_empty);
 | 
						|
    bool sub_not_empty = (files.find("/not_empty") != std::end(files)) || (files.find("not_empty") != std::end(files));
 | 
						|
    REQUIRE(sub_not_empty);
 | 
						|
}
 | 
						|
 | 
						|
File FindFileByName(const File f[], int count, const char *name)
 | 
						|
{
 | 
						|
    for (int i=0; i<count; i++) {
 | 
						|
      if (!strcmp(name, f[i].name())) return f[i];
 | 
						|
    }
 | 
						|
    return f[0];
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Listfiles.ino example", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(128, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.format());
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
 | 
						|
    createFile("file1", "hello");
 | 
						|
    createFile("file2", "hola");
 | 
						|
    createFile("dir1/file3", "nihao");
 | 
						|
    createFile("dir2/dir3/file4", "bonjour");
 | 
						|
 | 
						|
    File root = FSTYPE.open("/", "r");
 | 
						|
    // LittleFS and SDFS are not guaranteed to put the names in order of creation, so
 | 
						|
    // manually look for them...
 | 
						|
    File f[4];
 | 
						|
    f[0] = root.openNextFile();
 | 
						|
    f[1] = root.openNextFile();
 | 
						|
    f[2] = root.openNextFile();
 | 
						|
    f[3] = root.openNextFile();
 | 
						|
    File file1 = FindFileByName(f, 4, "file1");
 | 
						|
    File file2 = FindFileByName(f, 4, "file2");
 | 
						|
    File dir1 = FindFileByName(f, 4, "dir1");
 | 
						|
    File dir1_file3 = dir1.openNextFile();
 | 
						|
    File dir2 = FindFileByName(f, 4, "dir2");
 | 
						|
    File dir2_dir3 = dir2.openNextFile();
 | 
						|
    File dir2_dir3_file4 = dir2_dir3.openNextFile();
 | 
						|
 | 
						|
    bool ok;
 | 
						|
    ok = root.isDirectory() && !root.isFile() && !strcmp(root.name(), "/");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = !file1.isDirectory() && file1.isFile() && !strcmp(file1.name(), "file1");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = !file2.isDirectory() && file2.isFile() && !strcmp(file2.name(), "file2");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = dir1.isDirectory() && !dir1.isFile() && !strcmp(dir1.name(), "dir1");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = !dir1_file3.isDirectory() && dir1_file3.isFile() && !strcmp(dir1_file3.name(), "file3") &&
 | 
						|
         !strcmp(dir1_file3.fullName(), "dir1/file3");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = dir2.isDirectory() && !dir2.isFile() && !strcmp(dir2.name(), "dir2");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = dir2_dir3.isDirectory() && !dir2_dir3.isFile() && !strcmp(dir2_dir3.name(), "dir3");
 | 
						|
    REQUIRE(ok);
 | 
						|
    ok = !dir2_dir3_file4.isDirectory() && dir2_dir3_file4.isFile() && !strcmp(dir2_dir3_file4.name(), "file4") &&
 | 
						|
         !strcmp(dir2_dir3_file4.fullName(), "dir2/dir3/file4");
 | 
						|
    REQUIRE(ok);
 | 
						|
 | 
						|
    REQUIRE(readFile("/file1") == "hello");
 | 
						|
    REQUIRE(readFile("file2") == "hola");
 | 
						|
    REQUIRE(readFile("dir1/file3") == "nihao");
 | 
						|
    REQUIRE(readFile("/dir2/dir3/file4") == "bonjour");
 | 
						|
}
 | 
						|
 | 
						|
#else // !FS_HAS_DIRS
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Dir lists all files", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
    createFile("/empty", "");
 | 
						|
    createFile("/not_empty", "some text");
 | 
						|
    createFile("/another", "more text");
 | 
						|
    createFile("/subdir/empty", "");
 | 
						|
    createFile("/subdir/not_empty", "text again");
 | 
						|
    auto files = listDir("/");
 | 
						|
    REQUIRE(files.size() == 5);
 | 
						|
    bool empty = (files.find("/empty") != std::end(files)) || (files.find("empty") != std::end(files));
 | 
						|
    REQUIRE(empty);
 | 
						|
    bool not_empty = (files.find("/not_empty") != std::end(files)) || (files.find("not_empty") != std::end(files));
 | 
						|
    REQUIRE(not_empty);
 | 
						|
    bool another = (files.find("/another") != std::end(files)) ||  (files.find("another") != std::end(files));
 | 
						|
    REQUIRE(another);
 | 
						|
    bool sub_empty = (files.find("/subdir/empty") != std::end(files)) || (files.find("subdir/empty") != std::end(files));
 | 
						|
    REQUIRE(sub_empty);
 | 
						|
    bool sub_not_empty = (files.find("/subdir/not_empty") != std::end(files)) || (files.find("subdir/not_empty") != std::end(files));
 | 
						|
    REQUIRE(sub_not_empty);
 | 
						|
}
 | 
						|
 | 
						|
TEST_CASE(TESTPRE "Multisplendored File::writes", TESTPAT)
 | 
						|
{
 | 
						|
    FS_MOCK_DECLARE(64, 8, 512, "");
 | 
						|
    REQUIRE(FSTYPE.begin());
 | 
						|
 | 
						|
    File f = FSTYPE.open("/file.txt", "w");
 | 
						|
    f.write('a');
 | 
						|
    f.write(65);
 | 
						|
    f.write("bbcc");
 | 
						|
    f.write("theend", 6);
 | 
						|
    char block[3]={'x','y','z'};
 | 
						|
    f.write(block, 3);
 | 
						|
    uint32_t bigone = 0x40404040;
 | 
						|
    f.write((const uint8_t*)&bigone, 4);
 | 
						|
    f.close();
 | 
						|
    REQUIRE(readFile("/file.txt") == "aAbbcctheendxyz@@@@");
 | 
						|
    File g = FSTYPE.open("/file.txt", "w");
 | 
						|
    g.write(0);
 | 
						|
    g.close();
 | 
						|
    g = FSTYPE.open("/file.txt", "r");
 | 
						|
    uint8_t u = 0x66;
 | 
						|
    g.read(&u, 1);
 | 
						|
    g.close();
 | 
						|
    REQUIRE(u == 0);
 | 
						|
}
 | 
						|
 | 
						|
#endif
 |