refactor: flatten repository structure to root and archive research notes
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestLocalRemoveSymlinkDoesNotDeleteTarget(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
outside := t.TempDir()
|
||||
target := filepath.Join(outside, "secret.txt")
|
||||
if err := os.WriteFile(target, []byte("keep"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
link := filepath.Join(root, "link")
|
||||
if err := os.Symlink(target, link); err != nil {
|
||||
t.Skipf("symlink unavailable: %v", err)
|
||||
}
|
||||
store := Local{Root: root}
|
||||
if err := store.Remove("link"); err != nil {
|
||||
t.Fatalf("remove symlink: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(target); err != nil {
|
||||
t.Fatalf("symlink removal must not delete target: %v", err)
|
||||
}
|
||||
if _, err := os.Lstat(link); !os.IsNotExist(err) {
|
||||
t.Fatalf("symlink should be removed, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLocalRejectsSymlinkEscapeAndAllowsNestedCreate(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
outside := t.TempDir()
|
||||
if err := os.WriteFile(filepath.Join(outside, "secret.txt"), []byte("secret"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(outside, filepath.Join(root, "escape")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
s := Local{Root: root}
|
||||
if _, err := s.Open("escape/secret.txt"); err == nil {
|
||||
t.Fatal("expected symlink escape to be rejected")
|
||||
}
|
||||
f, err := s.Create("a/b/c.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("nested create failed: %v", err)
|
||||
}
|
||||
_ = f.Close()
|
||||
}
|
||||
|
||||
func TestMoveToTrashPreservesRelativePathAndCleansOldEntries(t *testing.T) {
|
||||
root := t.TempDir()
|
||||
trash := t.TempDir()
|
||||
s := Local{Root: root}
|
||||
if err := os.MkdirAll(filepath.Join(root, "one", "two"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.WriteFile(filepath.Join(root, "one", "two", "same.txt"), []byte("x"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.MkdirAll(filepath.Join(trash, "old"), 0o755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
old := filepath.Join(trash, "old", "stale.txt")
|
||||
if err := os.WriteFile(old, []byte("old"), 0o644); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
oldTime := time.Now().Add(-31 * 24 * time.Hour)
|
||||
if err := os.Chtimes(old, oldTime, oldTime); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := s.MoveToTrash("one/two/same.txt", trash); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(trash, "one", "two", "same.txt")); err != nil {
|
||||
t.Fatalf("trash path not preserved: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(old); !os.IsNotExist(err) {
|
||||
t.Fatalf("stale trash entry was not cleaned: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCopyPathPreservesSymlink(t *testing.T) {
|
||||
src := filepath.Join(t.TempDir(), "link")
|
||||
dst := filepath.Join(t.TempDir(), "link")
|
||||
if err := os.Symlink("target", src); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := copyPath(src, dst); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got, err := os.Readlink(dst)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got != "target" {
|
||||
t.Fatalf("got symlink target %q", got)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user