package attach import ( "bytes" "encoding/hex" "errors" "os" "path/filepath" "runtime" "strings" "testing" ) // fakeDesktop stands in for whatever helper this machine would have used. // "cat" is the helper here: it exists everywhere this runs and it writes the // bytes it is given, which is all any of the real ones do. func fakeDesktop(t *testing.T, gs []grabber) { t.Helper() if runtime.GOOS == "windows" { t.Skip("the stand-in helper is a unix one") } old := grabbers grabbers = gs t.Cleanup(func() { grabbers = old }) } func writeTemp(t *testing.T, name string, data []byte) string { t.Helper() p := filepath.Join(t.TempDir(), name) if err := os.WriteFile(p, data, 0o644); err != nil { t.Fatal(err) } return p } func TestClipboardReadsWhatTheHelperWrites(t *testing.T) { want := tinyPNG(t) fakeDesktop(t, []grabber{{cmd: "cat", args: []string{writeTemp(t, "clip.png", want)}}}) im, err := Clipboard() if err != nil { t.Fatal(err) } if im.Media != "image/png" || !bytes.Equal(im.Data, want) { t.Errorf("got %s, %d bytes; want image/png, %d", im.Media, len(im.Data), len(want)) } if im.Origin != "clipboard" { t.Errorf("origin = %q", im.Origin) } } // Text on the clipboard is what ctrl-V usually finds, and it has to come back // as "no image" rather than as an error worth interrupting anyone over. func TestClipboardOfTextIsNoImage(t *testing.T) { fakeDesktop(t, []grabber{{cmd: "cat", args: []string{writeTemp(t, "clip.txt", []byte("some copied words"))}}}) if _, err := Clipboard(); !errors.Is(err, ErrNoImage) { t.Fatalf("err = %v; want ErrNoImage", err) } } // A helper that is not installed is not a failure: the next one in the list // may be the one this desktop uses. func TestClipboardFallsThroughToTheNextHelper(t *testing.T) { want := tinyPNG(t) fakeDesktop(t, []grabber{ {cmd: "codey-no-such-clipboard-helper"}, {cmd: "cat", args: []string{writeTemp(t, "clip.png", want)}}, }) im, err := Clipboard() if err != nil || !bytes.Equal(im.Data, want) { t.Fatalf("second helper not reached: %v", err) } } func TestClipboardWithNoHelperInstalledSaysSo(t *testing.T) { fakeDesktop(t, []grabber{{cmd: "codey-no-such-clipboard-helper"}}) _, err := Clipboard() if err == nil { t.Fatal("a machine with no helper reported success") } // The message has to name the fix; "no image" would send someone looking // at their clipboard instead of at their packages. if !strings.Contains(err.Error(), "helper") { t.Errorf("unhelpful message: %v", err) } } // An image found and too big is worth saying out loud, unlike an empty // clipboard: the person can see the screenshot they copied. func TestClipboardReportsAnOversizeImage(t *testing.T) { big := append(tinyPNG(t), make([]byte, MaxBytes)...) fakeDesktop(t, []grabber{{cmd: "cat", args: []string{writeTemp(t, "big.png", big)}}}) _, err := Clipboard() if !errors.Is(err, ErrTooBig) { t.Fatalf("err = %v; want ErrTooBig", err) } } func TestDecodeAppleScriptUnwrapsHexData(t *testing.T) { want := tinyPNG(t) out := "«data PNGf" + hex.EncodeToString(want) + "»\n" got, err := decodeAppleScript([]byte(out)) if err != nil || !bytes.Equal(got, want) { t.Fatalf("decode = %d bytes, %v; want %d bytes", len(got), err, len(want)) } } func TestDecodeAppleScriptOnAnEmptyClipboard(t *testing.T) { // osascript answers a clipboard with no PNG on it by failing, but an // empty or surprising line must not decode into rubbish either. if _, err := decodeAppleScript([]byte("\n")); err == nil { t.Error("nothing decoded into something") } } func TestDecodeHexLine(t *testing.T) { want := tinyPNG(t) got, err := decodeHexLine([]byte(strings.ToUpper(hex.EncodeToString(want)) + "\r\n")) if err != nil || !bytes.Equal(got, want) { t.Fatalf("decode = %d bytes, %v", len(got), err) } } // Whatever this machine is, it must offer some way to try. func TestDefaultGrabbersExist(t *testing.T) { if len(defaultGrabbers()) == 0 { t.Fatal("no clipboard helpers are even attempted on " + runtime.GOOS) } }