/*
* Copyright (c) Atmosphère-NX
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
namespace ams {
namespace fssrv::impl {
const char *GetExecutionDirectoryPath();
}
namespace {
void GetPath(char *dst, size_t dst_size, const char *src) {
if (fs::IsPathAbsolute(src)) {
util::SNPrintf(dst, dst_size, "%s", src);
} else {
util::SNPrintf(dst, dst_size, "%s%s", fssrv::impl::GetExecutionDirectoryPath(), src);
}
}
#define TEST_R_EXPECT(__EXPR__, __EXPECTED__) \
({ \
const Result __test_result = (__EXPR__); \
if (!(__EXPECTED__ ::Includes(__test_result))) { \
printf("Unexpected result: %s gave 0x%08x (2%03d-%04d)\n", # __EXPR__, __test_result.GetValue(), __test_result.GetModule(), __test_result.GetDescription()); \
return; \
} \
__test_result; \
})
#define TEST_R_TRY(__EXPR__) \
({ \
const Result __test_result = (__EXPR__); \
if (R_FAILED(__test_result)) { \
printf("Unexpected result: %s gave 0x%08x (2%03d-%04d)\n", # __EXPR__, __test_result.GetValue(), __test_result.GetModule(), __test_result.GetDescription()); \
return; \
} \
__test_result; \
})
u8 g_buffer[64_KB];
void DoFsTests() {
/* Declare buffer to hold any work paths we have. */
char path_buf[fs::EntryNameLengthMax + 1];
char path_buf2[fs::EntryNameLengthMax + 1];
#define FORMAT_PATH(S) ({ GetPath(path_buf, sizeof(path_buf), S); path_buf; })
#define FORMAT_PATH2(S) ({ GetPath(path_buf2, sizeof(path_buf2), S); path_buf2; })
AMS_UNUSED(path_buf);
AMS_UNUSED(path_buf2);
/* Clear anything from a previous test run, no obligation for this to succeed. */
fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/"));
/* Verify that the test directory does not exist. */
fs::DirectoryEntryType entry_type;
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/")), fs::ResultPathNotFound);
/* Create the subdirectory. */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/")));
/* Verify the test directory exists and is a directory. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* ==================================================================================================================== */
/* Create File */
/* ==================================================================================================================== */
/* Create a file. */
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound);
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/test_rand.bin"), sizeof(g_buffer)));
/* Check the file has correct entry type. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_rand.bin")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File);
/* Create already existing file -> fs::ResultPathAlreadyExists(). */
TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/test_rand.bin"), sizeof(g_buffer)), fs::ResultPathAlreadyExists);
/* Create already existing dir -> fs::ResultPathAlreadyExists(). */
TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/"), sizeof(g_buffer)), fs::ResultPathAlreadyExists);
/* Create file without parent existing -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::CreateFile(FORMAT_PATH("./test_dir/aaa/bbb.bin"), sizeof(g_buffer)), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Create Directory */
/* ==================================================================================================================== */
/* Create the subdirectory. */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/test_subdir/")));
/* Verify the test directory exists and is a directory. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_subdir/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* Create already existing file -> fs::ResultPathAlreadyExists(). */
TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathAlreadyExists);
/* Create already existing dir -> fs::ResultPathAlreadyExists(). */
TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/")), fs::ResultPathAlreadyExists);
/* Create dir without parent existing -> fs::ResultPathAlreadyExists(). */
TEST_R_EXPECT(fs::CreateDirectory(FORMAT_PATH("./test_dir/aaa/bbb/")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Delete File */
/* ==================================================================================================================== */
/* Delete file succeeds. */
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/tmp_for_delete.bin"), sizeof(g_buffer)));
TEST_R_TRY(fs::DeleteFile(FORMAT_PATH("./test_dir/tmp_for_delete.bin")));
/* Delete on invalid path -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteFile(FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound);
/* Delete on directory -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteFile(FORMAT_PATH("./test_dir/test_subdir/")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Delete Directory */
/* ==================================================================================================================== */
/* Delete dir succeeds. */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")));
TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")));
/* Delete on invalid path -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound);
/* Delete on file -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound);
/* Delete on non-empty directory -> fs::ResultDirectoryNotEmpty(). */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/tmp_for_delete/tmp_for_delete.bin"), sizeof(g_buffer)));
TEST_R_EXPECT(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")), fs::ResultDirectoryNotEmpty);
TEST_R_TRY(fs::DeleteFile(FORMAT_PATH("./test_dir/tmp_for_delete/tmp_for_delete.bin")));
TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/tmp_for_delete/")));
/* ==================================================================================================================== */
/* Delete Directory Recursively */
/* ==================================================================================================================== */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/")));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/y.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/z.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/0/")));
/* Verify the test directory still exists and is a directory. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* Verify the recursive directory doesn't. */
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/0/")), fs::ResultPathNotFound);
/* Delete recursive on invalid path -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound);
/* Delete recursive on file -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Clean Directory Recursively */
/* ==================================================================================================================== */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/")));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/y.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/0/z.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/x.bin"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/0/0/0/0/0/0/0/0/0/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/000/b/0/0/0/x.bin"), 0));
TEST_R_TRY(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/0/")));
/* Verify the recursive directory still exists and is a directory. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/0/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* Delete the recursive directory. */
TEST_R_TRY(fs::DeleteDirectory(FORMAT_PATH("./test_dir/0/")));
/* Clean recursive on invalid path -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/invalid/")), fs::ResultPathNotFound);
/* Clean recursive on file -> fs::ResultPathNotFound(). */
TEST_R_EXPECT(fs::CleanDirectoryRecursively(FORMAT_PATH("./test_dir/test_rand.bin")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Rename File */
/* ==================================================================================================================== */
/* Rename succeeds. */
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/a.bin"), 1_KB));
TEST_R_TRY(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/b.bin")));
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin")), fs::ResultPathNotFound);
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/b.bin")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File);
/* Rename non-existing -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/invalid"), FORMAT_PATH2("./test_dir/invalid2")), fs::ResultPathNotFound);
/* Rename valid -> already existing gives fs::ResultPathAlreadyExists */
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/a.bin"), 1_KB));
TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/b.bin")), fs::ResultPathAlreadyExists);
/* Rename valid -> directory gives fs::ResultPathAlreadyExists */
TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/test_subdir/")), fs::ResultPathAlreadyExists);
/* Rename directory -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::RenameFile(FORMAT_PATH("./test_dir/test_subdir/"), FORMAT_PATH2("./test_dir/c.bin")), fs::ResultPathNotFound);
/* Invalid doesn't affect the file/dir. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File);
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/test_subdir/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* ==================================================================================================================== */
/* Rename Directory */
/* ==================================================================================================================== */
/* Rename succeeds. */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/")));
TEST_R_TRY(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/dir_b/")));
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/")), fs::ResultPathNotFound);
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_b/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* Rename non-existing -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/invalid"), FORMAT_PATH2("./test_dir/invalid2")), fs::ResultPathNotFound);
/* Rename valid -> already existing gives fs::ResultPathAlreadyExists */
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/")));
TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/dir_b/")), fs::ResultPathAlreadyExists);
/* Rename valid -> file gives fs::ResultPathAlreadyExists */
TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/dir_a/"), FORMAT_PATH2("./test_dir/a.bin")), fs::ResultPathAlreadyExists);
/* Rename file -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::RenameDirectory(FORMAT_PATH("./test_dir/a.bin"), FORMAT_PATH2("./test_dir/dir_c/")), fs::ResultPathNotFound);
/* Invalid doesn't affect the file/dir. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File);
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* ==================================================================================================================== */
/* Get Entry Type */
/* ==================================================================================================================== */
/* File -> file. */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/a.bin")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_File);
/* Dir -> dir */
TEST_R_TRY(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/dir_a/")));
AMS_ABORT_UNLESS(entry_type == fs::DirectoryEntryType_Directory);
/* Invalid -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::GetEntryType(std::addressof(entry_type), FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Get Free Space Size */
/* ==================================================================================================================== */
s64 free_size = 0;
TEST_R_TRY(fs::GetFreeSpaceSize(std::addressof(free_size), FORMAT_PATH("./test_dir/")));
AMS_ABORT_UNLESS(free_size > 0);
/* ==================================================================================================================== */
/* Get Total Space Size */
/* ==================================================================================================================== */
s64 total_size = 0;
TEST_R_TRY(fs::GetTotalSpaceSize(std::addressof(total_size), FORMAT_PATH("./test_dir/")));
AMS_ABORT_UNLESS(total_size >= free_size);
/* ==================================================================================================================== */
/* Get File Time Stamp */
/* ==================================================================================================================== */
/* Get timestamp succeeds. */
fs::FileTimeStamp timestamp;
TEST_R_TRY(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/a.bin")));
AMS_ABORT_UNLESS(timestamp.create.value > 0);
AMS_ABORT_UNLESS(timestamp.access.value > 0);
AMS_ABORT_UNLESS(timestamp.modify.value > 0);
AMS_ABORT_UNLESS(!timestamp.is_local_time);
/* Invalid -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/invalid")), fs::ResultPathNotFound);
/* Directory -> fs::ResultPathNotFound */
TEST_R_EXPECT(fs::GetFileTimeStamp(std::addressof(timestamp), FORMAT_PATH("./test_dir/dir_a/")), fs::ResultPathNotFound);
/* ==================================================================================================================== */
/* Query Entry */
/* ==================================================================================================================== */
TEST_R_EXPECT(fs::SetConcatenationFileAttribute(FORMAT_PATH("./test_dir/")), fs::ResultUnsupportedOperation);
/* ==================================================================================================================== */
/* Open File */
/* ==================================================================================================================== */
/* Open valid succeeds. */
fs::FileHandle file;
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend));
fs::CloseFile(file);
/* Open invalid -> path not found. */
TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/invalid"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend), fs::ResultPathNotFound);
/* Open directory -> path not found. */
TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenMode_ReadWrite | fs::OpenMode_AllowAppend), fs::ResultPathNotFound);
/* Open with invalid mode -> fs::ResultInvalidOpenMode */
TEST_R_EXPECT(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), static_cast(~0u)), fs::ResultInvalidOpenMode);
/* Read only file is read only. */
{
s64 file_size;
u8 buf[1_KB];
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* File size matches create. */
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
/* Read succeeds. */
TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf)));
/* Completely empty read ok. */
TEST_R_TRY(fs::ReadFile(file, 0, nullptr, 0));
/* Flush succeeds. */
TEST_R_TRY(fs::FlushFile(file));
}
/* Incorrect arguments return incorrect results. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::ReadFile(file, -1, buf, sizeof(buf)), fs::ResultOutOfRange);
}
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::ReadFile(file, 0, buf, -1), fs::ResultOutOfRange);
}
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::ReadFile(file, 0, nullptr, sizeof(buf)), fs::ResultNullptrArgument);
}
/* Write fails. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::WriteFile(file, 0, g_buffer, sizeof(g_buffer), fs::WriteOption::None), fs::ResultWriteNotPermitted);
}
/* Set size fails. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::SetFileSize(file, 2_KB), fs::ResultWriteNotPermitted);
}
/* File size unchanged by bad set size. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
}
}
/* Write only file is writable but not readable. */
{
s64 file_size;
u8 buf[1_KB];
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Write succeeds. */
std::memset(buf, 0xcc, sizeof(buf));
TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::None));
/* Flush succeeds. */
TEST_R_TRY(fs::FlushFile(file));
/* Write with flush succeeds. */
TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::Flush));
/* Get size succeeds. */
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
/* Set size succeeds. */
TEST_R_TRY(fs::SetFileSize(file, 2_KB));
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 2_KB);
/* Write at updated size works. */
TEST_R_TRY(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::Flush));
/* Truncate down succeeds. */
TEST_R_TRY(fs::SetFileSize(file, 1_KB));
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
/* Completely empty write ok. */
TEST_R_TRY(fs::WriteFile(file, 0, nullptr, 0, fs::WriteOption::Flush));
}
/* Incorrect arguments return incorrect results. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::WriteFile(file, -1, buf, sizeof(buf), fs::WriteOption::None), fs::ResultOutOfRange);
}
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::WriteFile(file, 0, buf, -1, fs::WriteOption::None), fs::ResultOutOfRange);
}
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::WriteFile(file, 0, nullptr, sizeof(buf), fs::WriteOption::None), fs::ResultNullptrArgument);
}
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::None), fs::ResultFileExtensionWithoutOpenModeAllowAppend);
}
/* Read fails. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_EXPECT(fs::ReadFile(file, 0, buf, sizeof(buf)), fs::ResultReadNotPermitted);
}
/* Appending works with OpenMode_AllowAppend. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_Write | fs::OpenMode_AllowAppend));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
for (size_t i = 0; i < sizeof(buf); ++i) {
buf[i] = static_cast(i);
}
TEST_R_TRY(fs::WriteFile(file, 1_KB, buf, sizeof(buf), fs::WriteOption::Flush));
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 2_KB);
}
/* Data is persistent. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/a.bin"), fs::OpenMode_ReadWrite));
ON_SCOPE_EXIT { fs::CloseFile(file); };
TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf)));
for (size_t i = 0; i < 1_KB; ++i) {
AMS_ABORT_UNLESS(buf[i] == 0xCC);
}
TEST_R_TRY(fs::ReadFile(file, 1_KB, buf, sizeof(buf)));
for (size_t i = 0; i < 1_KB; ++i) {
AMS_ABORT_UNLESS(buf[i] == static_cast(i));
}
TEST_R_TRY(fs::WriteFile(file, 0, buf, sizeof(buf), fs::WriteOption::Flush));
TEST_R_TRY(fs::SetFileSize(file, 1_KB));
TEST_R_TRY(fs::GetFileSize(std::addressof(file_size), file));
AMS_ABORT_UNLESS(file_size == 1_KB);
TEST_R_TRY(fs::ReadFile(file, 0, buf, sizeof(buf)));
for (size_t i = 0; i < 1_KB; ++i) {
AMS_ABORT_UNLESS(buf[i] == static_cast(i));
}
}
}
/* More involved file data test using random buffer. */
{
u8 buf[1_KB];
/* Write random data. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/test_rand.bin"), fs::OpenMode_Write));
ON_SCOPE_EXIT { fs::CloseFile(file); };
/* Get a bunch of random data. */
os::GenerateRandomBytes(g_buffer, sizeof(g_buffer));
/* Write it to disk. */
TEST_R_TRY(fs::WriteFile(file, 0, g_buffer, sizeof(g_buffer), fs::WriteOption::None));
TEST_R_TRY(fs::FlushFile(file));
}
/* Read and verify random data. */
{
TEST_R_TRY(fs::OpenFile(std::addressof(file), FORMAT_PATH("./test_dir/test_rand.bin"), fs::OpenMode_Read));
ON_SCOPE_EXIT { fs::CloseFile(file); };
u32 ofs;
for (size_t i = 0; i < 1000; ++i) {
os::GenerateRandomBytes(std::addressof(ofs), sizeof(ofs));
ofs %= (sizeof(g_buffer) - sizeof(buf));
TEST_R_TRY(fs::ReadFile(file, ofs, buf, sizeof(buf)));
AMS_ABORT_UNLESS(std::memcmp(buf, g_buffer + ofs, sizeof(buf)) == 0);
}
}
}
/* ==================================================================================================================== */
/* Open Directory */
/* ==================================================================================================================== */
fs::DirectoryHandle dir;
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize));
fs::CloseDirectory(dir);
/* Open invalid -> path not found. */
TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/invalid"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize), fs::ResultPathNotFound);
/* Open file -> path not found. */
TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/a.bin"), fs::OpenDirectoryMode_All | fs::OpenDirectoryMode_NotRequireFileSize), fs::ResultPathNotFound);
/* Open with invalid mode -> fs::ResultInvalidOpenMode */
TEST_R_EXPECT(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), static_cast(~0u)), fs::ResultInvalidOpenMode);
/* Populate test directory with three files and two dirs. */
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f0"), 0));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f1"), 1_KB));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/f2"), 0x42069));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d0")));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d1")));
TEST_R_TRY(fs::CreateFile(FORMAT_PATH("./test_dir/dir_a/d0/file"), 0));
TEST_R_TRY(fs::CreateDirectory(FORMAT_PATH("./test_dir/dir_a/d0/dir/")));
/* Directory tests. */
{
bool seen_file[3];
bool seen_dir[2];
constexpr s64 NumFiles = util::size(seen_file);
constexpr s64 NumDirs = util::size(seen_dir);
constexpr s64 NumAll = NumFiles + NumDirs;
fs::DirectoryEntry entries[2 * NumAll];
s64 entry_count;
auto ResetSeenFiles = [&] () { for (auto &b : seen_file) { b = false; } };
auto ResetSeenDirs = [&] () { for (auto &b : seen_dir) { b = false; } };
auto ResetSeenAll = [&] () { ResetSeenFiles(); ResetSeenDirs(); };
auto CheckSeenFiles = [&] () { for (const auto b : seen_file) { AMS_ABORT_UNLESS(b); } };
auto CheckSeenDirs = [&] () { for (const auto b : seen_dir) { AMS_ABORT_UNLESS(b); } };
auto CheckSeenAll = [&] () { CheckSeenFiles(); CheckSeenDirs(); };
auto CheckNotSeenFiles = [&] () { for (const auto b : seen_file) { AMS_ABORT_UNLESS(!b); } };
auto CheckNotSeenDirs = [&] () { for (const auto b : seen_dir) { AMS_ABORT_UNLESS(!b); } };
auto CheckDirectoryEntry = [&] (const fs::DirectoryEntry &entry) {
/* Check name. */
AMS_ABORT_UNLESS(entry.name[0] == 'f' || entry.name[0] == 'd');
AMS_ABORT_UNLESS('0' <= entry.name[1] && entry.name[1] <= '9');
AMS_ABORT_UNLESS(entry.name[2] == 0);
/* Check type. */
if (entry.name[0] == 'f') {
AMS_ABORT_UNLESS(entry.type == fs::DirectoryEntryType_File);
/* If file, check size. */
switch (entry.name[1]) {
case '0': AMS_ABORT_UNLESS(entry.file_size == 0); break;
case '1': AMS_ABORT_UNLESS(entry.file_size == 1_KB); break;
case '2': AMS_ABORT_UNLESS(entry.file_size == 0x42069); break;
}
AMS_ABORT_UNLESS(!seen_file[(entry.name[1] - '0')]);
seen_file[(entry.name[1] - '0')] = true;
} else {
AMS_ABORT_UNLESS(entry.type == fs::DirectoryEntryType_Directory);
AMS_ABORT_UNLESS(!seen_dir[(entry.name[1] - '0')]);
seen_dir[(entry.name[1] - '0')] = true;
}
};
/* Get EntryCount is correct. */
{
/* All returns all entries. */
{
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumAll);
}
/* File returns only files, and does not count things in subdirectories. */
{
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_File));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumFiles);
}
/* Dir returns only dirs, and does not count things in subdirectories. */
{
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_Directory));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumDirs);
}
}
/* Read is correct, N at a time. */
for (s64 at_a_time = 1; at_a_time <= 2 * NumAll; ++at_a_time) {
/* All returns all entries. */
{
ResetSeenAll();
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_All));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumAll);
s64 remaining = entry_count;
while (remaining > 0) {
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur <= remaining);
AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining));
for (s64 i = 0; i < cur; ++i) {
CheckDirectoryEntry(entries[i]);
}
remaining -= cur;
}
CheckSeenAll();
/* Read succeeds at end of dir. */
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur == 0);
/* Get entry count still shows correct value. */
s64 entry_count2;
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir));
AMS_ABORT_UNLESS(entry_count2 == entry_count);
}
/* File returns only files. */
{
ResetSeenAll();
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_File));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumFiles);
s64 remaining = entry_count;
while (remaining > 0) {
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur <= remaining);
AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining));
for (s64 i = 0; i < cur; ++i) {
CheckDirectoryEntry(entries[i]);
}
remaining -= cur;
}
CheckSeenFiles();
CheckNotSeenDirs();
/* Read succeeds at end of dir. */
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur == 0);
/* Get entry count still shows correct value. */
s64 entry_count2;
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir));
AMS_ABORT_UNLESS(entry_count2 == entry_count);
}
/* Directory returns only dirs. */
{
ResetSeenAll();
TEST_R_TRY(fs::OpenDirectory(std::addressof(dir), FORMAT_PATH("./test_dir/dir_a/"), fs::OpenDirectoryMode_Directory));
ON_SCOPE_EXIT { fs::CloseDirectory(dir); };
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count), dir));
AMS_ABORT_UNLESS(entry_count == NumDirs);
s64 remaining = entry_count;
while (remaining > 0) {
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur <= remaining);
AMS_ABORT_UNLESS(cur == std::min(at_a_time, remaining));
for (s64 i = 0; i < cur; ++i) {
CheckDirectoryEntry(entries[i]);
}
remaining -= cur;
}
CheckSeenDirs();
CheckNotSeenFiles();
/* Read succeeds at end of dir. */
s64 cur;
TEST_R_TRY(fs::ReadDirectory(std::addressof(cur), entries, dir, at_a_time));
AMS_ABORT_UNLESS(cur == 0);
/* Get entry count still shows correct value. */
s64 entry_count2;
TEST_R_TRY(fs::GetDirectoryEntryCount(std::addressof(entry_count2), dir));
AMS_ABORT_UNLESS(entry_count2 == entry_count);
}
}
}
/* ==================================================================================================================== */
/* Cleanup */
/* ==================================================================================================================== */
TEST_R_TRY(fs::DeleteDirectoryRecursively(FORMAT_PATH("./test_dir/")));
}
}
void Main() {
fs::SetEnabledAutoAbort(false);
printf("Doing FS test!\n");
DoFsTests();
printf("All tests completed!\n");
}
}