Files
cthulhu/internal/app/tentacle_clipboard_test.go

94 lines
3.1 KiB
Go

package app
import (
"bytes"
"context"
"image"
"image/png"
"net/url"
"os"
"os/exec"
"path/filepath"
"testing"
"time"
"git.stormux.org/storm/cthulhu/internal/tentaclewire"
)
func TestTentacleClipboardRequiresOneLocalFile(t *testing.T) {
for _, raw := range []string{"file:///tmp/a%20b\r\n", "copy\nfile:///tmp/a%20b\n", "cut\nfile://localhost/tmp/a%20b\n", "file:///tmp/a%20b\x00", "file:///tmp/a%20b\r\n\x00", "copy\nfile:///tmp/a%20b\n\x00"} {
value, err := singleClipboardURI(raw)
if err != nil || value.Path != "/tmp/a b" {
t.Fatal(value, err)
}
}
for _, raw := range []string{"", "file:///tmp/a\nfile:///tmp/b\n", "file://remote/tmp/a", "https://example.org/a", "file:///tmp/a?query", "file:///tmp/a\x00file:///tmp/b", "file:///tmp/a\x00\x00", "file:///tmp/a%00b", "file:///tmp/a\nfile:///tmp/b\x00"} {
if _, err := singleClipboardURI(raw); err == nil {
t.Fatal("accepted", raw)
}
}
}
func TestNativeTentacleClipboardTargetsAndTemporaryImage(t *testing.T) {
if os.Getenv("CTHULHU_NATIVE_INTERNAL_UI") != "1" {
t.Skip("requires isolated Xorg clipboard")
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
set := func(target string, data []byte) {
t.Helper()
command := exec.CommandContext(ctx, "xclip", "-selection", "clipboard", "-in", "-target", target)
command.Stdin = bytes.NewReader(data)
if err := command.Run(); err != nil {
t.Fatal(err)
}
}
path := filepath.Join(t.TempDir(), "one file.txt")
if err := os.WriteFile(path, []byte("fixture"), 0600); err != nil {
t.Fatal(err)
}
uri := (&url.URL{Scheme: "file", Path: path}).String()
var item tentaclewire.Item
var err error
for _, selection := range []struct{ target, data string }{
{"text/uri-list", uri + "\r\n"},
{"text/uri-list", uri + "\x00"}, // GTK file-manager selection terminator.
{"x-special/gnome-copied-files", "copy\n" + uri + "\n\x00"},
} {
set(selection.target, []byte(selection.data))
item, err = readTentacleClipboard(ctx)
if err != nil || item.Path != path || item.Temporary {
t.Fatal(selection.target, item, err)
}
}
set("text/uri-list", []byte(uri+"\nfile:///tmp/another\n"))
if _, err = readTentacleClipboard(ctx); err == nil {
t.Fatal("accepted multiple file-manager clipboard items")
}
text := "one\ntwo é猫"
if err = copyTentacleText(ctx, text); err != nil {
t.Fatal(err)
}
item, err = readTentacleClipboard(ctx)
if err != nil || item.Text != text || item.Path != "" {
t.Fatal(item, err)
}
var bitmap bytes.Buffer
if err = png.Encode(&bitmap, image.NewRGBA(image.Rect(0, 0, 2, 2))); err != nil {
t.Fatal(err)
}
set("image/png", bitmap.Bytes())
item, err = readTentacleClipboard(ctx)
if err != nil || !item.Temporary || filepath.Base(item.Path) != "clipboard.png" {
t.Fatal(item, err)
}
defer os.RemoveAll(filepath.Dir(item.Path))
data, err := os.ReadFile(item.Path)
if err != nil || !bytes.Equal(data, bitmap.Bytes()) {
t.Fatal("temporary clipboard image changed", err)
}
if info, _ := os.Stat(item.Path); info.Mode().Perm() != 0600 {
t.Fatal("temporary image is not private")
}
}