...

Source file src/github.com/gin-gonic/gin/binding/multipart_form_mapping_test.go

Documentation: github.com/gin-gonic/gin/binding

     1  // Copyright 2019 Gin Core Team. All rights reserved.
     2  // Use of this source code is governed by a MIT style
     3  // license that can be found in the LICENSE file.
     4  
     5  package binding
     6  
     7  import (
     8  	"bytes"
     9  	"io"
    10  	"mime/multipart"
    11  	"net/http"
    12  	"testing"
    13  
    14  	"github.com/stretchr/testify/assert"
    15  )
    16  
    17  func TestFormMultipartBindingBindOneFile(t *testing.T) {
    18  	var s struct {
    19  		FileValue   multipart.FileHeader     `form:"file"`
    20  		FilePtr     *multipart.FileHeader    `form:"file"`
    21  		SliceValues []multipart.FileHeader   `form:"file"`
    22  		SlicePtrs   []*multipart.FileHeader  `form:"file"`
    23  		ArrayValues [1]multipart.FileHeader  `form:"file"`
    24  		ArrayPtrs   [1]*multipart.FileHeader `form:"file"`
    25  	}
    26  	file := testFile{"file", "file1", []byte("hello")}
    27  
    28  	req := createRequestMultipartFiles(t, file)
    29  	err := FormMultipart.Bind(req, &s)
    30  	assert.NoError(t, err)
    31  
    32  	assertMultipartFileHeader(t, &s.FileValue, file)
    33  	assertMultipartFileHeader(t, s.FilePtr, file)
    34  	assert.Len(t, s.SliceValues, 1)
    35  	assertMultipartFileHeader(t, &s.SliceValues[0], file)
    36  	assert.Len(t, s.SlicePtrs, 1)
    37  	assertMultipartFileHeader(t, s.SlicePtrs[0], file)
    38  	assertMultipartFileHeader(t, &s.ArrayValues[0], file)
    39  	assertMultipartFileHeader(t, s.ArrayPtrs[0], file)
    40  }
    41  
    42  func TestFormMultipartBindingBindTwoFiles(t *testing.T) {
    43  	var s struct {
    44  		SliceValues []multipart.FileHeader   `form:"file"`
    45  		SlicePtrs   []*multipart.FileHeader  `form:"file"`
    46  		ArrayValues [2]multipart.FileHeader  `form:"file"`
    47  		ArrayPtrs   [2]*multipart.FileHeader `form:"file"`
    48  	}
    49  	files := []testFile{
    50  		{"file", "file1", []byte("hello")},
    51  		{"file", "file2", []byte("world")},
    52  	}
    53  
    54  	req := createRequestMultipartFiles(t, files...)
    55  	err := FormMultipart.Bind(req, &s)
    56  	assert.NoError(t, err)
    57  
    58  	assert.Len(t, s.SliceValues, len(files))
    59  	assert.Len(t, s.SlicePtrs, len(files))
    60  	assert.Len(t, s.ArrayValues, len(files))
    61  	assert.Len(t, s.ArrayPtrs, len(files))
    62  
    63  	for i, file := range files {
    64  		assertMultipartFileHeader(t, &s.SliceValues[i], file)
    65  		assertMultipartFileHeader(t, s.SlicePtrs[i], file)
    66  		assertMultipartFileHeader(t, &s.ArrayValues[i], file)
    67  		assertMultipartFileHeader(t, s.ArrayPtrs[i], file)
    68  	}
    69  }
    70  
    71  func TestFormMultipartBindingBindError(t *testing.T) {
    72  	files := []testFile{
    73  		{"file", "file1", []byte("hello")},
    74  		{"file", "file2", []byte("world")},
    75  	}
    76  
    77  	for _, tt := range []struct {
    78  		name string
    79  		s    any
    80  	}{
    81  		{"wrong type", &struct {
    82  			Files int `form:"file"`
    83  		}{}},
    84  		{"wrong array size", &struct {
    85  			Files [1]*multipart.FileHeader `form:"file"`
    86  		}{}},
    87  		{"wrong slice type", &struct {
    88  			Files []int `form:"file"`
    89  		}{}},
    90  	} {
    91  		req := createRequestMultipartFiles(t, files...)
    92  		err := FormMultipart.Bind(req, tt.s)
    93  		assert.Error(t, err)
    94  	}
    95  }
    96  
    97  type testFile struct {
    98  	Fieldname string
    99  	Filename  string
   100  	Content   []byte
   101  }
   102  
   103  func createRequestMultipartFiles(t *testing.T, files ...testFile) *http.Request {
   104  	var body bytes.Buffer
   105  
   106  	mw := multipart.NewWriter(&body)
   107  	for _, file := range files {
   108  		fw, err := mw.CreateFormFile(file.Fieldname, file.Filename)
   109  		assert.NoError(t, err)
   110  
   111  		n, err := fw.Write(file.Content)
   112  		assert.NoError(t, err)
   113  		assert.Equal(t, len(file.Content), n)
   114  	}
   115  	err := mw.Close()
   116  	assert.NoError(t, err)
   117  
   118  	req, err := http.NewRequest("POST", "/", &body)
   119  	assert.NoError(t, err)
   120  
   121  	req.Header.Set("Content-Type", MIMEMultipartPOSTForm+"; boundary="+mw.Boundary())
   122  	return req
   123  }
   124  
   125  func assertMultipartFileHeader(t *testing.T, fh *multipart.FileHeader, file testFile) {
   126  	assert.Equal(t, file.Filename, fh.Filename)
   127  	assert.Equal(t, int64(len(file.Content)), fh.Size)
   128  
   129  	fl, err := fh.Open()
   130  	assert.NoError(t, err)
   131  
   132  	body, err := io.ReadAll(fl)
   133  	assert.NoError(t, err)
   134  	assert.Equal(t, string(file.Content), string(body))
   135  
   136  	err = fl.Close()
   137  	assert.NoError(t, err)
   138  }
   139  

View as plain text