#include "Test.h" #include "Command.h" #include "Editor.h" #include "tests/TestHarness.h" // for ktet::InstallDefaultCommandsOnce #include #include #include #include #include #include namespace fs = std::filesystem; static void write_file_bytes(const std::string &path, const std::string &bytes) { std::ofstream out(path, std::ios::binary | std::ios::trunc); out.write(bytes.data(), (std::streamsize) bytes.size()); } TEST (SwapCleanup_ResetJournalOnSave) { ktet::InstallDefaultCommandsOnce(); const fs::path xdg_root = fs::temp_directory_path() / (std::string("kte_ut_xdg_state_swap_cleanup_") + std::to_string((int) ::getpid())); fs::remove_all(xdg_root); fs::create_directories(xdg_root); const char *old_xdg_p = std::getenv("XDG_STATE_HOME"); const std::string old_xdg = old_xdg_p ? std::string(old_xdg_p) : std::string(); const std::string xdg_s = xdg_root.string(); setenv("XDG_STATE_HOME", xdg_s.c_str(), 1); const std::string path = (xdg_root / "work" / "file.txt").string(); fs::create_directories((xdg_root / "work")); std::remove(path.c_str()); write_file_bytes(path, "base\n"); Editor ed; ed.SetDimensions(24, 80); // Seed scratch buffer so OpenFile can reuse it. ed.AddBuffer(Buffer()); std::string err; ASSERT_TRUE(ed.OpenFile(path, err)); Buffer *b = ed.CurrentBuffer(); ASSERT_TRUE(b != nullptr); // Edit to ensure swap is created. ASSERT_TRUE(Execute(ed, CommandId::MoveFileStart)); ASSERT_TRUE(Execute(ed, CommandId::InsertText, "X")); ASSERT_TRUE(b->Dirty()); ed.Swap()->Flush(b); const std::string swp = kte::SwapManager::ComputeSwapPathForTests(*b); ASSERT_TRUE(fs::exists(swp)); // Save should reset/delete the journal. ASSERT_TRUE(Execute(ed, CommandId::Save)); ed.Swap()->Flush(b); ASSERT_TRUE(!fs::exists(swp)); // Subsequent edits should recreate a fresh swap. ASSERT_TRUE(Execute(ed, CommandId::InsertText, "Y")); ed.Swap()->Flush(b); ASSERT_TRUE(fs::exists(swp)); // Cleanup. ed.Swap()->Detach(b); std::remove(path.c_str()); std::remove(swp.c_str()); if (!old_xdg.empty()) setenv("XDG_STATE_HOME", old_xdg.c_str(), 1); else unsetenv("XDG_STATE_HOME"); fs::remove_all(xdg_root); } TEST (SwapCleanup_PruneSwapDir_ByAge) { const fs::path xdg_root = fs::temp_directory_path() / (std::string("kte_ut_xdg_state_swap_prune_") + std::to_string((int) ::getpid())); fs::remove_all(xdg_root); fs::create_directories(xdg_root); const char *old_xdg_p = std::getenv("XDG_STATE_HOME"); const std::string old_xdg = old_xdg_p ? std::string(old_xdg_p) : std::string(); const std::string xdg_s = xdg_root.string(); setenv("XDG_STATE_HOME", xdg_s.c_str(), 1); const fs::path swapdir = xdg_root / "kte" / "swap"; fs::create_directories(swapdir); const fs::path oldp = swapdir / "old.swp"; const fs::path newp = swapdir / "new.swp"; const fs::path keep = swapdir / "note.txt"; write_file_bytes(oldp.string(), "x"); write_file_bytes(newp.string(), "y"); write_file_bytes(keep.string(), "z"); // Make old.swp look old (2 days ago) and new.swp recent. std::error_code ec; fs::last_write_time(oldp, fs::file_time_type::clock::now() - std::chrono::hours(48), ec); fs::last_write_time(newp, fs::file_time_type::clock::now(), ec); kte::SwapManager sm; kte::SwapConfig cfg; cfg.prune_on_startup = false; cfg.prune_max_age_days = 1; cfg.prune_max_files = 0; // disable count-based pruning for this test sm.SetConfig(cfg); sm.PruneSwapDir(); ASSERT_TRUE(!fs::exists(oldp)); ASSERT_TRUE(fs::exists(newp)); ASSERT_TRUE(fs::exists(keep)); // Cleanup. std::remove(newp.string().c_str()); std::remove(keep.string().c_str()); if (!old_xdg.empty()) setenv("XDG_STATE_HOME", old_xdg.c_str(), 1); else unsetenv("XDG_STATE_HOME"); fs::remove_all(xdg_root); }