zip_test.go raw
1 package bridge
2
3 import (
4 "archive/zip"
5 "bytes"
6 crand "crypto/rand"
7 "strings"
8 "testing"
9
10 bridgesmtp "next.orly.dev/pkg/bridge/smtp"
11 )
12
13 func TestZipParts_HTMLOnly(t *testing.T) {
14 data, err := ZipParts("<html><body>Hello</body></html>", nil)
15 if err != nil {
16 t.Fatalf("ZipParts: %v", err)
17 }
18
19 // Verify it's a valid zip
20 r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
21 if err != nil {
22 t.Fatalf("read zip: %v", err)
23 }
24
25 if len(r.File) != 1 {
26 t.Fatalf("expected 1 file, got %d", len(r.File))
27 }
28 if r.File[0].Name != "body.html" {
29 t.Errorf("file name = %q, want body.html", r.File[0].Name)
30 }
31 }
32
33 func TestZipParts_WithAttachments(t *testing.T) {
34 attachments := []bridgesmtp.Attachment{
35 {Filename: "test.pdf", ContentType: "application/pdf", Data: []byte("pdf-content")},
36 {Filename: "image.png", ContentType: "image/png", Data: []byte("png-content")},
37 }
38
39 data, err := ZipParts("", attachments)
40 if err != nil {
41 t.Fatalf("ZipParts: %v", err)
42 }
43
44 r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
45 if err != nil {
46 t.Fatalf("read zip: %v", err)
47 }
48
49 if len(r.File) != 2 {
50 t.Fatalf("expected 2 files, got %d", len(r.File))
51 }
52
53 names := map[string]bool{}
54 for _, f := range r.File {
55 names[f.Name] = true
56 }
57
58 if !names["test.pdf"] {
59 t.Error("missing test.pdf in zip")
60 }
61 if !names["image.png"] {
62 t.Error("missing image.png in zip")
63 }
64 }
65
66 func TestZipParts_HTMLAndAttachments(t *testing.T) {
67 attachments := []bridgesmtp.Attachment{
68 {Filename: "doc.txt", ContentType: "text/plain", Data: []byte("content")},
69 }
70
71 data, err := ZipParts("<p>HTML</p>", attachments)
72 if err != nil {
73 t.Fatalf("ZipParts: %v", err)
74 }
75
76 r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
77 if err != nil {
78 t.Fatalf("read zip: %v", err)
79 }
80
81 if len(r.File) != 2 { // body.html + doc.txt
82 t.Errorf("expected 2 files, got %d", len(r.File))
83 }
84 }
85
86 func TestZipParts_Empty(t *testing.T) {
87 // Both empty — should produce a valid (empty) zip
88 data, err := ZipParts("", nil)
89 if err != nil {
90 t.Fatalf("ZipParts: %v", err)
91 }
92
93 r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
94 if err != nil {
95 t.Fatalf("read zip: %v", err)
96 }
97 if len(r.File) != 0 {
98 t.Errorf("expected 0 files, got %d", len(r.File))
99 }
100 }
101
102 func TestZipParts_ExceedsSizeLimit(t *testing.T) {
103 // crypto/rand data is incompressible — zip output will be >= input size
104 bigData := make([]byte, 26*1024*1024) // 26MB
105 crand.Read(bigData)
106
107 attachments := []bridgesmtp.Attachment{
108 {Filename: "huge.bin", ContentType: "application/octet-stream", Data: bigData},
109 }
110
111 _, err := ZipParts("", attachments)
112 if err == nil {
113 t.Fatal("expected error for exceeding zip size limit")
114 }
115 if !strings.Contains(err.Error(), "limit") {
116 t.Errorf("error should mention limit, got: %v", err)
117 }
118 }
119
120 func TestZipParts_EmptyFilename(t *testing.T) {
121 attachments := []bridgesmtp.Attachment{
122 {Filename: "", ContentType: "application/octet-stream", Data: []byte("data")},
123 }
124
125 data, err := ZipParts("", attachments)
126 if err != nil {
127 t.Fatalf("ZipParts: %v", err)
128 }
129
130 r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
131 if err != nil {
132 t.Fatalf("read zip: %v", err)
133 }
134
135 if r.File[0].Name != "attachment" {
136 t.Errorf("fallback name = %q, want 'attachment'", r.File[0].Name)
137 }
138 }
139