package application import ( "context" "strings" "testing" ) type fakeOSSProvider struct { key string data []byte contentType string url string deletedKey string } func (f *fakeOSSProvider) Upload(_ context.Context, key string, data []byte, contentType string) (string, error) { f.key = key f.data = append([]byte(nil), data...) f.contentType = contentType if f.url == "" { return "https://cdn.example.com/" + key, nil } return f.url, nil } func (f *fakeOSSProvider) Name() string { return "fake" } func (f *fakeOSSProvider) Delete(_ context.Context, key string) error { f.deletedKey = key return nil } type fakeSummarizer struct { prompt string url string text string } func (f *fakeSummarizer) SummarizeImage(_ context.Context, prompt string, imageURL string) (string, error) { f.prompt = prompt f.url = imageURL if f.text == "" { return "summary text", nil } return f.text, nil } func TestCaptureSummaryServiceUploadsSummarizesAndCopies(t *testing.T) { ctx := context.Background() provider := &fakeOSSProvider{} summarizer := &fakeSummarizer{} clip := &fakeClipboard{} svc := &CaptureSummaryService{ Provider: provider, Summarizer: summarizer, Clipboard: clip, Prompt: "describe screenshot", PathPrefix: "snapgo/", } uploaded, err := svc.UploadImage(ctx, []byte("png")) if err != nil { t.Fatalf("upload image: %v", err) } if provider.contentType != "image/png" { t.Fatalf("expected image/png content type, got %q", provider.contentType) } if string(provider.data) != "png" { t.Fatalf("expected uploaded png bytes, got %q", string(provider.data)) } summary, err := svc.Summarize(ctx, uploaded.URL) if err != nil { t.Fatalf("summarize: %v", err) } if summarizer.prompt != "describe screenshot" { t.Fatalf("expected prompt forwarded, got %q", summarizer.prompt) } if summarizer.url != uploaded.URL { t.Fatalf("expected uploaded url forwarded, got %q", summarizer.url) } if summary != "summary text" { t.Fatalf("expected summary text, got %q", summary) } if err := svc.CopySummary(ctx, summary); err != nil { t.Fatalf("copy summary: %v", err) } if clip.text != "summary text" { t.Fatalf("expected summary copied, got %q", clip.text) } } func TestCaptureSummaryServiceInlineDataURL(t *testing.T) { svc := &CaptureSummaryService{MaxInlineBytes: 10} if !svc.CanInline([]byte("small")) { t.Fatalf("expected 5-byte payload to be inlinable under 10-byte cap") } if svc.CanInline([]byte("this is definitely too big")) { t.Fatalf("expected oversized payload to be rejected for inlining") } url := svc.InlineDataURL([]byte("png")) if !strings.HasPrefix(url, "data:image/png;base64,") { t.Fatalf("expected base64 data URL prefix, got %q", url) } if strings.Contains(url, "https://") { t.Fatalf("inline URL must not be a remote URL, got %q", url) } } func TestCaptureSummaryServiceDeleteUploadedUsesDeleter(t *testing.T) { provider := &fakeOSSProvider{} svc := &CaptureSummaryService{Provider: provider} if err := svc.DeleteUploaded(context.Background(), "snapgo/a.png"); err != nil { t.Fatalf("delete uploaded: %v", err) } if provider.deletedKey != "snapgo/a.png" { t.Fatalf("expected object deleted, got %q", provider.deletedKey) } } func TestCaptureSummaryServiceDeleteUploadedNoDeleterIsNoop(t *testing.T) { // A provider without Delete must not error when cleanup is requested. svc := &CaptureSummaryService{Provider: nonDeletingProvider{}} if err := svc.DeleteUploaded(context.Background(), "snapgo/a.png"); err != nil { t.Fatalf("expected no-op delete, got %v", err) } } type nonDeletingProvider struct{} func (nonDeletingProvider) Upload(_ context.Context, _ string, _ []byte, _ string) (string, error) { return "https://cdn.example.com/x.png", nil } func (nonDeletingProvider) Name() string { return "no-delete" }