diff --git a/Core/Util/StorageTest.cpp b/Core/Util/StorageTest.cpp index 2067fe1180..28bb8b4c08 100644 --- a/Core/Util/StorageTest.cpp +++ b/Core/Util/StorageTest.cpp @@ -26,6 +26,7 @@ #include "Common/Log.h" #include "Common/StringUtils.h" #include "Common/TimeUtil.h" +#include "Core/Util/MemStick.h" #include "Core/Util/StorageTest.h" // A test returns an empty string if it passed, and what went wrong if it didn't. @@ -245,6 +246,91 @@ int RunStorageTests(const Path &root, const std::function std::string { + const Path src = scratch / "move1/old"; + const Path dest = scratch / "move1/new"; + CHECK(makeMemstick(src)); + CHECK(File::CreateFullPath(dest)); + bool committed = false; + MoveProgressReporter progress; + MoveResult *result = MoveDirectoryContentsSafe(src, dest, progress, [&]() { committed = true; return true; }); + const bool success = result && result->success; + delete result; + CHECK(success); + CHECK(committed); + CHECK(ReadAll(dest / "PSP/SAVEDATA/GAME1/DATA.BIN") == "save"); + CHECK(ReadAll(dest / "PSP/SYSTEM/ppsspp.ini") == "ini"); + CHECK(!File::Exists(src / "PSP/SAVEDATA")); + CHECK(!File::Exists(src / "PSP/SYSTEM")); + return ""; + }); + + run("MoveCopy", [&]() -> std::string { + // A non-empty SAVEDATA already there can't be renamed over, which forces the copy. + const Path src = scratch / "move2/old"; + const Path dest = scratch / "move2/new"; + CHECK(makeMemstick(src)); + CHECK(File::CreateFullPath(dest / "PSP/SAVEDATA/GAME2")); + CHECK(Write(dest / "PSP/SAVEDATA/GAME2/DATA.BIN", "other")); + bool originalsThereAtCommit = false; + MoveProgressReporter progress; + MoveResult *result = MoveDirectoryContentsSafe(src, dest, progress, [&]() { + originalsThereAtCommit = File::Exists(src / "PSP/SAVEDATA/GAME1/DATA.BIN"); + return true; + }); + const bool success = result && result->success; + delete result; + CHECK(success); + CHECK(originalsThereAtCommit); + CHECK(ReadAll(dest / "PSP/SAVEDATA/GAME1/DATA.BIN") == "save"); + CHECK(ReadAll(dest / "PSP/SAVEDATA/GAME2/DATA.BIN") == "other"); + CHECK(ReadAll(dest / "PSP/SYSTEM/ppsspp.ini") == "ini"); + CHECK(!File::Exists(src / "PSP/SAVEDATA/GAME1/DATA.BIN")); + return ""; + }); + + run("MoveUndo", [&]() -> std::string { + // Fails at the end, after part was renamed and part copied, so everything has to be put back. + const Path src = scratch / "move3/old"; + const Path dest = scratch / "move3/new"; + CHECK(makeMemstick(src)); + CHECK(File::CreateFullPath(src / "PSP/AAA")); + CHECK(Write(src / "PSP/AAA/A.BIN", "a")); + CHECK(File::CreateFullPath(dest / "PSP/SAVEDATA/GAME2")); + CHECK(Write(dest / "PSP/SAVEDATA/GAME2/DATA.BIN", "other")); + MoveProgressReporter progress; + MoveResult *result = MoveDirectoryContentsSafe(src, dest, progress, []() { return false; }); + const bool undone = result && !result->success && !result->partlyMoved; + delete result; + CHECK(undone); + CHECK(ReadAll(src / "PSP/AAA/A.BIN") == "a"); + CHECK(ReadAll(src / "PSP/SAVEDATA/GAME1/DATA.BIN") == "save"); + CHECK(ReadAll(src / "PSP/SYSTEM/ppsspp.ini") == "ini"); + CHECK(!File::Exists(dest / "PSP/AAA")); + CHECK(!File::Exists(dest / "PSP/SAVEDATA/GAME1")); + CHECK(ReadAll(dest / "PSP/SAVEDATA/GAME2/DATA.BIN") == "other"); + return ""; + }); + + run("FolderChecks", [&]() -> std::string { + const Path ms = scratch / "check/ms"; + CHECK(makeMemstick(ms)); + CHECK(FolderSeemsToBeUsed(ms)); + CHECK(CheckNewMemstickFolder(ms, Path()) == MemstickFolderCheck::OK); + CHECK(CheckNewMemstickFolder(ms / "PSP/SAVEDATA", ms) == MemstickFolderCheck::INSIDE_CURRENT); + // A PSP folder under another name. + CHECK(File::Rename(ms / "PSP", ms / "Renamed")); + CHECK(CheckNewMemstickFolder(ms / "Renamed", Path()) == MemstickFolderCheck::LOOKS_LIKE_PSP_FOLDER); + CHECK(CanSwitchMemstickFolderTo(ms)); + return ""; + }); + // Not a pass/fail test: the cost of the calls the emulator makes most, for comparing implementations. // On content URIs each is a call into Java and a binder transaction to the provider. run("Timing", [&]() -> std::string { diff --git a/Core/Util/StorageTest.h b/Core/Util/StorageTest.h index 2103cecde1..635c684472 100644 --- a/Core/Util/StorageTest.h +++ b/Core/Util/StorageTest.h @@ -29,7 +29,7 @@ struct StorageTestResult { std::string detail; }; -// Exercises the file functions in a scratch folder inside root, deleted again +// Exercises the file functions and the memory stick move in a scratch folder inside root, deleted again // afterwards. root can be a native path, or on Android a picked folder (a content URI), which is the case // the unit tests can't reach: they have no Java VM. report is called after each test, on the calling thread. // Returns the number of failures. diff --git a/docs/android-device-testing.md b/docs/android-device-testing.md index 8d308fa367..a89ef785b3 100644 --- a/docs/android-device-testing.md +++ b/docs/android-device-testing.md @@ -114,7 +114,8 @@ Two things to know when reading its results: ## Running the storage tests in the app `Core/Util/StorageTest.cpp` exercises the file functions (create, overwrite, list, rename, move, copy, -delete, odd names, free space) in a scratch folder, and times the calls the emulator makes most. The +delete, odd names, free space) and the memory stick move (rename, copy, undo, folder checks) in a scratch +folder, and times the calls the emulator makes most. The `Storage` unit test runs them on a native folder; to run them on a picked folder, through the content URI code: