Files

143 lines
5.1 KiB
Go

package vault
import (
"errors"
"os"
"path/filepath"
"strings"
"testing"
)
func TestImageMoveUpdatesLocalReferences(t *testing.T) {
v := newVault(t)
if err := os.MkdirAll(filepath.Join(v.Root(), "assets"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(v.Root(), "assets/原图.png"), []byte("image"), 0o644); err != nil {
t.Fatal(err)
}
content := "![图](../assets/原图.png?q=1#part \"标题\")\n[ref]: <../assets/原图.png>\n<img src=\"../assets/原图.png?q=1&amp;x=2\">\n`![](../assets/原图.png)`\n\n```md\n![](../assets/原图.png)\n```\n![](https://example.com/assets/原图.png)\n![](../assets/其他.png)\n"
if _, err := v.Write("notes/a.md", []byte(content), Precondition{}); err != nil {
t.Fatal(err)
}
if _, err := v.Move("assets/原图.png", "elsewhere/新图 #.png"); err != nil {
t.Fatal(err)
}
out, _, err := v.Read("notes/a.md")
if err != nil {
t.Fatal(err)
}
want := strings.ReplaceAll(content, "../assets/原图.png", "../elsewhere/新图%20%23.png")
want = strings.ReplaceAll(want, "`![](../elsewhere/新图%20%23.png)`", "`![](../assets/原图.png)`")
want = strings.ReplaceAll(want, "```md\n![](../elsewhere/新图%20%23.png)", "```md\n![](../assets/原图.png)")
if string(out) != want {
t.Fatalf("链接改写不符:\n%s\n期望:\n%s", out, want)
}
if _, err := v.Move("elsewhere/新图 #.png", "elsewhere/新图.jpg"); !errors.Is(err, ErrInvalidPath) {
t.Fatalf("不能用重命名改变图片格式:%v", err)
}
item, err := v.Delete("elsewhere/新图 #.png")
if err != nil {
t.Fatal(err)
}
if item.Assets != "" {
t.Fatal("图片不应带走同名笔记附件目录")
}
if _, err := v.Restore(item.ID); err != nil {
t.Fatal(err)
}
f, _, err := v.OpenRaw("elsewhere/新图 #.png")
if err != nil {
t.Fatal(err)
}
f.Close()
}
func TestImageMovePreservesMultilineMarkdownAndIgnoresLiteralPaths(t *testing.T) {
v := newVault(t)
if err := os.WriteFile(filepath.Join(v.Root(), "old.png"), []byte("image"), 0o644); err != nil {
t.Fatal(err)
}
content := "> ![图片][pic]\r\n>\r\n> [pic]: old.png \"[示例](old.png)\"\r\n\n![跨行](\nold.png\n)\n\n普通文字 ](old.png)\n\n[^1]: old.png\n\n`![代码](old.png)`\n\n> ```md\n> ![代码块](old.png)\n> ```\n"
if _, err := v.Write("文章.md", []byte(content), Precondition{}); err != nil {
t.Fatal(err)
}
if _, err := v.Move("old.png", "new.png"); err != nil {
t.Fatal(err)
}
body, _, err := v.Read("文章.md")
if err != nil {
t.Fatal(err)
}
want := strings.Replace(content, "[pic]: old.png", "[pic]: new.png", 1)
want = strings.Replace(want, "![跨行](\nold.png", "![跨行](\nnew.png", 1)
if string(body) != want {
t.Fatalf("应只改写真正的图片引用:\n%s\n期望:\n%s", body, want)
}
}
func TestReplaceImagePreservesPathAndUploadContents(t *testing.T) {
v := newVault(t)
link, err := v.SaveAsset("a.md", "old.png", strings.NewReader("original"), 100)
if err != nil {
t.Fatal(err)
}
link = strings.TrimPrefix(link, "./")
if err := v.ReplaceImage(link, "replacement.PNG", strings.NewReader("replacement"), 100); err != nil {
t.Fatal(err)
}
newLink, err := v.SaveAsset("a.md", "old.png", strings.NewReader("original"), 100)
if err != nil {
t.Fatal(err)
}
newLink = strings.TrimPrefix(newLink, "./")
again, err := v.SaveAsset("a.md", "old.png", strings.NewReader("original"), 100)
if err != nil || strings.TrimPrefix(again, "./") != newLink || newLink == link {
t.Fatalf("替换后的去重不符:%q %q %q %v", link, newLink, again, err)
}
for name, want := range map[string]string{link: "replacement", newLink: "original"} {
data, err := os.ReadFile(filepath.Join(v.Root(), name))
if err != nil || string(data) != want {
t.Fatalf("图片内容错误:%q %q %v", name, data, err)
}
}
for _, tc := range []struct {
path, name, data string
limit int64
want error
}{
{link, "x.jpg", "new", 100, ErrInvalidPath},
{link, "x.png", "", 100, ErrInvalidPath},
{link, "x.png", "too big", 1, ErrTooLarge},
{"missing.png", "x.png", "new", 100, ErrNotFound},
{"../escape.png", "x.png", "new", 100, ErrInvalidPath},
{"a.md", "x.md", "new", 100, ErrInvalidPath},
} {
if err := v.ReplaceImage(tc.path, tc.name, strings.NewReader(tc.data), tc.limit); !errors.Is(err, tc.want) {
t.Errorf("替换 %s:得到 %v,期望 %v", tc.path, err, tc.want)
}
}
data, err := os.ReadFile(filepath.Join(v.Root(), link))
if err != nil || string(data) != "replacement" {
t.Fatalf("无效替换不能影响原图:%q %v", data, err)
}
}
func TestImagesDoNotExposeOrModifySymlinks(t *testing.T) {
v := newVault(t)
outside := filepath.Join(t.TempDir(), "private.png")
if err := os.WriteFile(outside, []byte("private"), 0o600); err != nil {
t.Fatal(err)
}
if err := os.Symlink(outside, filepath.Join(v.Root(), "link.png")); err != nil {
t.Fatal(err)
}
entries, err := v.Tree()
if err != nil || len(entries) != 0 {
t.Fatalf("图片列表不应公开符号链接:%v %v", entries, err)
}
if err := v.ReplaceImage("link.png", "x.png", strings.NewReader("new"), 100); !errors.Is(err, ErrInvalidPath) {
t.Fatalf("不能替换仓库外文件:%v", err)
}
}