...

Source file src/github.com/go-kivik/kivik/v4/attachments_test.go

Documentation: github.com/go-kivik/kivik/v4

     1  // Licensed under the Apache License, Version 2.0 (the "License"); you may not
     2  // use this file except in compliance with the License. You may obtain a copy of
     3  // the License at
     4  //
     5  //  http://www.apache.org/licenses/LICENSE-2.0
     6  //
     7  // Unless required by applicable law or agreed to in writing, software
     8  // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
     9  // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    10  // License for the specific language governing permissions and limitations under
    11  // the License.
    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