1
2
3
4
5
6
7
8
9
10
11
12
13 package kivik
14
15 import (
16 "encoding/json"
17 "errors"
18 "io"
19 "net/http"
20 "strconv"
21 "strings"
22 "testing"
23
24 "github.com/google/go-cmp/cmp"
25 "gitlab.com/flimzy/testy"
26
27 "github.com/go-kivik/kivik/v4/driver"
28 internal "github.com/go-kivik/kivik/v4/int/errors"
29 "github.com/go-kivik/kivik/v4/int/mock"
30 )
31
32 func TestAttachmentMarshalJSON(t *testing.T) {
33 type tst struct {
34 att *Attachment
35 expected string
36 err string
37 }
38 tests := testy.NewTable()
39 tests.Add("foo.txt", tst{
40 att: &Attachment{
41 Content: io.NopCloser(strings.NewReader("test attachment\n")),
42 Filename: "foo.txt",
43 ContentType: "text/plain",
44 },
45 expected: `{
46 "content_type": "text/plain",
47 "data": "dGVzdCBhdHRhY2htZW50Cg=="
48 }`,
49 })
50 tests.Add("revpos", tst{
51 att: &Attachment{
52 Content: io.NopCloser(strings.NewReader("test attachment\n")),
53 Filename: "foo.txt",
54 ContentType: "text/plain",
55 RevPos: 3,
56 },
57 expected: `{
58 "content_type": "text/plain",
59 "data": "dGVzdCBhdHRhY2htZW50Cg==",
60 "revpos": 3
61 }`,
62 })
63 tests.Add("follows", tst{
64 att: &Attachment{
65 Content: io.NopCloser(strings.NewReader("test attachment\n")),
66 Filename: "foo.txt",
67 Follows: true,
68 ContentType: "text/plain",
69 RevPos: 3,
70 },
71 expected: `{
72 "content_type": "text/plain",
73 "follows": true,
74 "revpos": 3
75 }`,
76 })
77 tests.Add("read error", tst{
78 att: &Attachment{
79 Content: io.NopCloser(&errorReader{}),
80 Filename: "foo.txt",
81 ContentType: "text/plain",
82 },
83 err: "json: error calling MarshalJSON for type *kivik.Attachment: errorReader",
84 })
85 tests.Add("stub", tst{
86 att: &Attachment{
87 Content: io.NopCloser(strings.NewReader("content")),
88 Stub: true,
89 Filename: "foo.txt",
90 ContentType: "text/plain",
91 Size: 7,
92 },
93 expected: `{
94 "content_type": "text/plain",
95 "length": 7,
96 "stub": true
97 }`,
98 })
99
100 tests.Run(t, func(t *testing.T, test tst) {
101 result, err := json.Marshal(test.att)
102 if !testy.ErrorMatches(test.err, err) {
103 t.Errorf("Unexpected error: %s", err)
104 }
105 if d := testy.DiffJSON([]byte(test.expected), result); d != nil {
106 t.Error(d)
107 }
108 })
109 }
110
111 func TestAttachmentUnmarshalJSON(t *testing.T) {
112 tests := []struct {
113 name string
114 input string
115
116 body string
117 expected *Attachment
118 err string
119 }{
120 {
121 name: "stub",
122 input: `{
123 "content_type": "text/plain",
124 "stub": true
125 }`,
126 expected: &Attachment{
127 ContentType: "text/plain",
128 Stub: true,
129 },
130 },
131 {
132 name: "simple",
133 input: `{
134 "content_type": "text/plain",
135 "data": "dGVzdCBhdHRhY2htZW50Cg=="
136 }`,
137 body: "test attachment\n",
138 expected: &Attachment{
139 ContentType: "text/plain",
140 },
141 },
142 }
143 for _, test := range tests {
144 t.Run(test.name, func(t *testing.T) {
145 result := new(Attachment)
146 err := json.Unmarshal([]byte(test.input), result)
147 if !testy.ErrorMatches(test.err, err) {
148 t.Errorf("Unexpected error: %s", err)
149 }
150 var body []byte
151 content := result.Content
152 t.Cleanup(func() {
153 _ = content.Close()
154 })
155 body, err = io.ReadAll(result.Content)
156 if err != nil {
157 t.Fatal(err)
158 }
159 result.Content = nil
160 if d := testy.DiffText(test.body, string(body)); d != nil {
161 t.Errorf("Unexpected body:\n%s", d)
162 }
163 if d := testy.DiffInterface(test.expected, result); d != nil {
164 t.Errorf("Unexpected result:\n%s", d)
165 }
166 })
167 }
168 }
169
170 func TestAttachmentsUnmarshalJSON(t *testing.T) {
171 tests := []struct {
172 name string
173 input string
174
175 expected Attachments
176 err string
177 }{
178 {
179 name: "no attachments",
180 input: "{}",
181 expected: Attachments{},
182 },
183 {
184 name: "one attachment",
185 input: `{
186 "foo.txt": {
187 "content_type": "text/plain",
188 "data": "dGVzdCBhdHRhY2htZW50Cg=="
189 }
190 }`,
191 expected: Attachments{
192 "foo.txt": &Attachment{
193 Filename: "foo.txt",
194 ContentType: "text/plain",
195 },
196 },
197 },
198 }
199 for _, test := range tests {
200 t.Run(test.name, func(t *testing.T) {
201 var att Attachments
202 err := json.Unmarshal([]byte(test.input), &att)
203 if !testy.ErrorMatches(test.err, err) {
204 t.Errorf("Unexpected error: %s", err)
205 }
206 for _, v := range att {
207 _ = v.Content.Close()
208 v.Content = nil
209 }
210 if d := testy.DiffInterface(test.expected, att); d != nil {
211 t.Error(d)
212 }
213 })
214 }
215 }
216
217 func TestAttachmentsIteratorNext(t *testing.T) {
218 tests := []struct {
219 name string
220 iter *AttachmentsIterator
221 expected *Attachment
222 status int
223 err string
224 }{
225 {
226 name: "error",
227 iter: &AttachmentsIterator{
228 atti: &mock.Attachments{
229 NextFunc: func(_ *driver.Attachment) error {
230 return &internal.Error{Status: http.StatusBadGateway, Err: errors.New("error")}
231 },
232 },
233 },
234 status: http.StatusBadGateway,
235 err: "error",
236 },
237 {
238 name: "success",
239 iter: &AttachmentsIterator{
240 atti: &mock.Attachments{
241 NextFunc: func(att *driver.Attachment) error {
242 *att = driver.Attachment{
243 Filename: "foo.txt",
244 }
245 return nil
246 },
247 },
248 },
249 expected: &Attachment{
250 Filename: "foo.txt",
251 },
252 },
253 }
254 for _, test := range tests {
255 t.Run(test.name, func(t *testing.T) {
256 result, err := test.iter.Next()
257 if d := internal.StatusErrorDiff(test.err, test.status, err); d != "" {
258 t.Error(d)
259 }
260 if d := testy.DiffInterface(test.expected, result); d != nil {
261 t.Error(d)
262 }
263 })
264 }
265 }
266
267 func TestAttachments_Next_resets_iterator_value(t *testing.T) {
268 idx := 0
269 atts := &AttachmentsIterator{
270 atti: &mock.Attachments{
271 NextFunc: func(att *driver.Attachment) error {
272 idx++
273 switch idx {
274 case 1:
275 att.Filename = strconv.Itoa(idx)
276 return nil
277 case 2:
278 return nil
279 }
280 return io.EOF
281 },
282 },
283 }
284
285 wantFilenames := []string{"1", ""}
286 gotFilenames := []string{}
287 for {
288 att, err := atts.Next()
289 if err == io.EOF {
290 break
291 }
292 if err != nil {
293 t.Fatal(err)
294 }
295 gotFilenames = append(gotFilenames, att.Filename)
296
297 }
298 if d := cmp.Diff(wantFilenames, gotFilenames); d != "" {
299 t.Error(d)
300 }
301 }
302
View as plain text