Add test for Git editor swap cleanup and improve swap file handling
- Added `test_swap_git_editor.cc` to verify proper swap file cleanup during Git editor workflows. Ensures no stale swap files are left after editor closure. - Updated swap handling logic in `Editor.cc` to always remove swap files on buffer closure during normal exit, preventing accumulation of leftover files. - Bumped version to 1.6.5 in `CMakeLists.txt`.
This commit is contained in:
@@ -4,7 +4,7 @@ project(kte)
|
|||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
set(KTE_VERSION "1.6.4")
|
set(KTE_VERSION "1.6.5")
|
||||||
|
|
||||||
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
# Default to terminal-only build to avoid SDL/OpenGL dependency by default.
|
||||||
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
# Enable with -DBUILD_GUI=ON when SDL2/OpenGL/Freetype are available.
|
||||||
@@ -310,6 +310,7 @@ if (BUILD_TESTS)
|
|||||||
tests/test_swap_replay.cc
|
tests/test_swap_replay.cc
|
||||||
tests/test_swap_recovery_prompt.cc
|
tests/test_swap_recovery_prompt.cc
|
||||||
tests/test_swap_cleanup.cc
|
tests/test_swap_cleanup.cc
|
||||||
|
tests/test_swap_git_editor.cc
|
||||||
tests/test_piece_table.cc
|
tests/test_piece_table.cc
|
||||||
tests/test_search.cc
|
tests/test_search.cc
|
||||||
tests/test_search_replace_flow.cc
|
tests/test_search_replace_flow.cc
|
||||||
|
|||||||
@@ -486,9 +486,10 @@ Editor::CloseBuffer(std::size_t index)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (swap_) {
|
if (swap_) {
|
||||||
// If the buffer is clean, remove its swap file when closing.
|
// Always remove swap file when closing a buffer on normal exit.
|
||||||
// (Crash recovery is unaffected: on crash, close paths are not executed.)
|
// Swap files are for crash recovery; on clean close, we don't need them.
|
||||||
swap_->Detach(&buffers_[index], !buffers_[index].Dirty());
|
// This prevents stale swap files from accumulating (e.g., when used as git editor).
|
||||||
|
swap_->Detach(&buffers_[index], true);
|
||||||
buffers_[index].SetSwapRecorder(nullptr);
|
buffers_[index].SetSwapRecorder(nullptr);
|
||||||
}
|
}
|
||||||
buffers_.erase(buffers_.begin() + static_cast<std::ptrdiff_t>(index));
|
buffers_.erase(buffers_.begin() + static_cast<std::ptrdiff_t>(index));
|
||||||
|
|||||||
94
tests/test_swap_git_editor.cc
Normal file
94
tests/test_swap_git_editor.cc
Normal file
@@ -0,0 +1,94 @@
|
|||||||
|
#include "Test.h"
|
||||||
|
|
||||||
|
#include "Command.h"
|
||||||
|
#include "Editor.h"
|
||||||
|
|
||||||
|
#include "tests/TestHarness.h"
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Simulate git editor workflow: open file, edit, save, edit more, close.
|
||||||
|
// The swap file should be deleted on close, not left behind.
|
||||||
|
TEST (SwapCleanup_GitEditorWorkflow)
|
||||||
|
{
|
||||||
|
ktet::InstallDefaultCommandsOnce();
|
||||||
|
|
||||||
|
const fs::path xdg_root = fs::temp_directory_path() /
|
||||||
|
(std::string("kte_ut_xdg_state_git_editor_") + 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);
|
||||||
|
|
||||||
|
// Simulate git's COMMIT_EDITMSG path
|
||||||
|
const std::string path = (xdg_root / ".git" / "COMMIT_EDITMSG").string();
|
||||||
|
fs::create_directories((xdg_root / ".git"));
|
||||||
|
std::remove(path.c_str());
|
||||||
|
write_file_bytes(path, "# Enter commit message\n");
|
||||||
|
|
||||||
|
Editor ed;
|
||||||
|
ed.SetDimensions(24, 80);
|
||||||
|
ed.AddBuffer(Buffer());
|
||||||
|
std::string err;
|
||||||
|
ASSERT_TRUE(ed.OpenFile(path, err));
|
||||||
|
Buffer *b = ed.CurrentBuffer();
|
||||||
|
ASSERT_TRUE(b != nullptr);
|
||||||
|
|
||||||
|
// User edits the file
|
||||||
|
ASSERT_TRUE(Execute(ed, CommandId::MoveFileStart));
|
||||||
|
ASSERT_TRUE(Execute(ed, CommandId::InsertText, "X"));
|
||||||
|
ASSERT_TRUE(b->Dirty());
|
||||||
|
|
||||||
|
// User saves (git will read this)
|
||||||
|
ASSERT_TRUE(Execute(ed, CommandId::Save));
|
||||||
|
ASSERT_TRUE(!b->Dirty());
|
||||||
|
ed.Swap()->Flush(b);
|
||||||
|
|
||||||
|
const std::string swp = kte::SwapManager::ComputeSwapPathForTests(*b);
|
||||||
|
// After save, swap should be deleted
|
||||||
|
ASSERT_TRUE(!fs::exists(swp));
|
||||||
|
|
||||||
|
// User makes more edits (common in git editor workflow - refining message)
|
||||||
|
ASSERT_TRUE(Execute(ed, CommandId::InsertText, "Y"));
|
||||||
|
ASSERT_TRUE(b->Dirty());
|
||||||
|
ed.Swap()->Flush(b);
|
||||||
|
|
||||||
|
// Now there's a new swap file for the unsaved edits
|
||||||
|
ASSERT_TRUE(fs::exists(swp));
|
||||||
|
|
||||||
|
// User closes the buffer (or kte exits)
|
||||||
|
// This simulates what happens when git is done and kte closes
|
||||||
|
const std::size_t idx = ed.CurrentBufferIndex();
|
||||||
|
ed.CloseBuffer(idx);
|
||||||
|
|
||||||
|
// The swap file should be deleted on close, even though buffer was dirty
|
||||||
|
// This prevents stale swap files when used as git editor
|
||||||
|
ASSERT_TRUE(!fs::exists(swp));
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
std::remove(path.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);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user