mirror of
https://github.com/duke-git/lancet.git
synced 2026-02-18 11:42:26 +08:00
Compare commits
3 Commits
8998dc35bb
...
v1.4.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5c01b7e675 | ||
|
|
0247ac232a | ||
|
|
e77354d7ff |
11
README.md
11
README.md
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -100,6 +100,9 @@ import "github.com/duke-git/lancet/convertor"
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DecodeByte)
|
||||
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#DeepClone)
|
||||
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#CopyProperties)
|
||||
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#ToInterface)
|
||||
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#Utf8ToGbk)
|
||||
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor.md#GbkToUtf8)
|
||||
|
||||
### 3. Cryptor package is for data encryption and decryption.
|
||||
|
||||
@@ -208,6 +211,7 @@ import "github.com/duke-git/lancet/fileutil"
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Zip)
|
||||
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ZipAppendEntry)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#UnZip)
|
||||
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#CurrentPath)
|
||||
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#IsZipFile)
|
||||
@@ -215,6 +219,7 @@ import "github.com/duke-git/lancet/fileutil"
|
||||
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#MTime)
|
||||
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#Sha)
|
||||
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#ReadCsvFile)
|
||||
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteCsvFile)
|
||||
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteStringToFile)
|
||||
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil.md#WriteBytesToFile)
|
||||
|
||||
@@ -275,6 +280,7 @@ import "github.com/duke-git/lancet/mathutil"
|
||||
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#LCM)
|
||||
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Cos)
|
||||
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Sin)
|
||||
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil.md#Log)
|
||||
|
||||
### 9. Netutil package contains functions to get net information and send http request.
|
||||
|
||||
@@ -320,6 +326,7 @@ import "github.com/duke-git/lancet/random"
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
|
||||
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
|
||||
|
||||
### 11. Retry package is for executing a function repeatedly until it was successful or canceled by the context.
|
||||
|
||||
@@ -427,7 +434,7 @@ import "github.com/duke-git/lancet/strutil"
|
||||
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#Trim)
|
||||
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#SplitAndTrim)
|
||||
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#HideString)
|
||||
|
||||
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil.md#RemoveWhiteSpace)
|
||||
### 14. System package contain some functions about os, runtime, shell command.
|
||||
|
||||
```go
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<br/>
|
||||
|
||||

|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://github.com/duke-git/lancet/releases)
|
||||
[](https://pkg.go.dev/github.com/duke-git/lancet)
|
||||
[](https://goreportcard.com/report/github.com/duke-git/lancet)
|
||||
[](https://github.com/duke-git/lancet/actions/workflows/codecov.yml)
|
||||
@@ -99,7 +99,9 @@ import "github.com/duke-git/lancet/convertor"
|
||||
- [DecodeByte](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DecodeByte)
|
||||
- [DeepClone](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#DeepClone)
|
||||
- [CopyProperties](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#CopyProperties)
|
||||
|
||||
- [ToInterface](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#ToInterface)
|
||||
- [Utf8ToGbk](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#Utf8ToGbk)
|
||||
- [GbkToUtf8](https://github.com/duke-git/lancet/blob/v1/docs/convertor_zh-CN.md#GbkToUtf8)
|
||||
### 3. cryptor 加密包支持数据加密和解密,获取 md5,hash 值。支持 base64, md5, hmac, aes, des, rsa。
|
||||
|
||||
```go
|
||||
@@ -207,6 +209,7 @@ import "github.com/duke-git/lancet/fileutil"
|
||||
- [ReadFileToString](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileToString)
|
||||
- [ReadFileByLine](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadFileByLine)
|
||||
- [Zip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Zip)
|
||||
- [ZipAppendEntry](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ZipAppendEntry)
|
||||
- [UnZip](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#UnZip)
|
||||
- [CurrentPath](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#CurrentPath)
|
||||
- [IsZipFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#IsZipFile)
|
||||
@@ -214,6 +217,7 @@ import "github.com/duke-git/lancet/fileutil"
|
||||
- [MTime](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#MTime)
|
||||
- [Sha](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#Sha)
|
||||
- [ReadCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#ReadCsvFile)
|
||||
- [WriteCsvFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteCsvFile)
|
||||
- [WriteStringToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteStringToFile)
|
||||
- [WriteBytesToFile](https://github.com/duke-git/lancet/blob/v1/docs/fileutil_zh-CN.md#WriteBytesToFile)
|
||||
|
||||
@@ -274,7 +278,7 @@ import "github.com/duke-git/lancet/mathutil"
|
||||
- [LCM](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#LCM)
|
||||
- [Cos](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Cos)
|
||||
- [Sin](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Sin)
|
||||
|
||||
- [Log](https://github.com/duke-git/lancet/blob/v1/docs/mathutil_zh-CN.md#Log)
|
||||
### 9. netutil 网络包支持获取 ip 地址,发送 http 请求。
|
||||
|
||||
```go
|
||||
@@ -319,6 +323,7 @@ import "github.com/duke-git/lancet/random"
|
||||
- [RandNumeral](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeral)
|
||||
- [RandNumeralOrLetter](https://github.com/duke-git/lancet/blob/v1/docs/random_zh-CN.md#RandNumeralOrLetter)
|
||||
- [UUIdV4](https://github.com/duke-git/lancet/blob/v1/docs/random.md#UUIdV4)
|
||||
- [RandUniqueIntSlice](https://github.com/duke-git/lancet/blob/v1/docs/random.md#RandUniqueIntSlice)
|
||||
|
||||
### 11. retry 重试执行函数直到函数运行成功或被 context cancel。
|
||||
|
||||
@@ -426,6 +431,7 @@ import "github.com/duke-git/lancet/strutil"
|
||||
- [Trim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#Trim)
|
||||
- [SplitAndTrim](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#SplitAndTrim)
|
||||
- [HideString](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#HideString)
|
||||
- [RemoveWhiteSpace](https://github.com/duke-git/lancet/blob/v1/docs/strutil_zh-CN.md#RemoveWhiteSpace)
|
||||
|
||||
### 14. system 包含 os, runtime, shell command 相关函数。
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ import (
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [ZipAppendEntry](#ZipAppendEntry)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
@@ -478,6 +479,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||
|
||||
<p>Append a single file or directory by fpath to an existing zip file.</p>
|
||||
|
||||
<b>Signature:</b>
|
||||
|
||||
```go
|
||||
func ZipAppendEntry(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>Example:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurrentPath">CurrentPath</span>
|
||||
|
||||
<p>return current absolute path.</p>
|
||||
|
||||
@@ -30,13 +30,14 @@ import (
|
||||
- [MiMeType](#MiMeType)
|
||||
- [IsExist](#IsExist)
|
||||
- [IsLink](#IsLink)
|
||||
- [IsDir](#IsDir)
|
||||
- [IsDir](#IsDir)画
|
||||
- [ListFileNames](#ListFileNames)
|
||||
- [RemoveFile](#RemoveFile)
|
||||
- [ReadFileToString](#ReadFileToString)
|
||||
- [ReadFileByLine](#ReadFileByLine)
|
||||
- [Zip](#Zip)
|
||||
- [UnZip](#UnZip)
|
||||
- [ZipAppendEntry](#ZipAppendEntry)
|
||||
- [CurrentPath](#CurrentPath)
|
||||
- [IsZipFile](#IsZipFile)
|
||||
- [FileSize](#FileSize)
|
||||
@@ -478,6 +479,34 @@ func main() {
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="ZipAppendEntry">ZipAppendEntry</span>
|
||||
|
||||
<p>通过将单个文件或目录追加到现有的zip文件</p>
|
||||
|
||||
<b>函数签名:</b>
|
||||
|
||||
```go
|
||||
func ZipAppendEntry(fpath string, destPath string) error
|
||||
```
|
||||
|
||||
<b>示例:</b>
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/duke-git/lancet/fileutil"
|
||||
)
|
||||
|
||||
func main() {
|
||||
err := fileutil.ZipAppendEntry("./test.txt", "./test.zip")
|
||||
if err != nil {
|
||||
fmt.Println(err)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### <span id="CurrentPath">CurrentPath</span>
|
||||
|
||||
<p>返回当前位置的绝对路径。</p>
|
||||
|
||||
132
fileutil/file.go
132
fileutil/file.go
@@ -178,44 +178,7 @@ func Zip(fpath string, destPath string) error {
|
||||
archive := zip.NewWriter(zipFile)
|
||||
defer archive.Close()
|
||||
|
||||
filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
|
||||
|
||||
if info.IsDir() {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
}
|
||||
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !info.IsDir() {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
_, err = io.Copy(writer, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
|
||||
return nil
|
||||
return addFileToArchive(fpath, archive)
|
||||
}
|
||||
|
||||
// UnZip unzip the file and save it to destPath
|
||||
@@ -260,6 +223,99 @@ func UnZip(zipFile string, destPath string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ZipAppendEntry append a single file or directory by fpath to an existing zip file.
|
||||
// Play: https://go.dev/play/p/cxvaT8TRNQp
|
||||
func ZipAppendEntry(fpath string, destPath string) error {
|
||||
tempFile, err := os.CreateTemp("", "temp.zip")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer os.Remove(tempFile.Name())
|
||||
|
||||
zipReader, err := zip.OpenReader(destPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archive := zip.NewWriter(tempFile)
|
||||
|
||||
for _, zipItem := range zipReader.File {
|
||||
zipItemReader, err := zipItem.Open()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header, err := zip.FileInfoHeader(zipItem.FileInfo())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
header.Name = zipItem.Name
|
||||
targetItem, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(targetItem, zipItemReader)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err = addFileToArchive(fpath, archive)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = zipReader.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = archive.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = tempFile.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return CopyFile(tempFile.Name(), destPath)
|
||||
}
|
||||
|
||||
func addFileToArchive(fpath string, archive *zip.Writer) error {
|
||||
err := filepath.Walk(fpath, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header, err := zip.FileInfoHeader(info)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
header.Name = strings.TrimPrefix(path, filepath.Dir(fpath)+"/")
|
||||
|
||||
if info.IsDir() {
|
||||
header.Name += "/"
|
||||
} else {
|
||||
header.Method = zip.Deflate
|
||||
writer, err := archive.CreateHeader(header)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
if _, err := io.Copy(writer, file); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return err
|
||||
}
|
||||
|
||||
func safeFilepathJoin(path1, path2 string) (string, error) {
|
||||
relPath, err := filepath.Rel(".", path2)
|
||||
if err != nil || strings.HasPrefix(relPath, "..") {
|
||||
|
||||
@@ -182,6 +182,44 @@ func TestZipAndUnZip(t *testing.T) {
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestZipAppendEntry(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestZipAppendEntry")
|
||||
|
||||
zipFile := "./text.zip"
|
||||
err := CopyFile("./testdata/file.go.zip", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
srcFile := "./text.txt"
|
||||
CreateFile(srcFile)
|
||||
|
||||
file, _ := os.OpenFile(srcFile, os.O_WRONLY|os.O_TRUNC, os.ModePerm)
|
||||
|
||||
_, err = file.WriteString("hello\nworld")
|
||||
if err != nil {
|
||||
t.Fail()
|
||||
}
|
||||
file.Close()
|
||||
|
||||
err = ZipAppendEntry(srcFile, zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
err = ZipAppendEntry("./testdata", zipFile)
|
||||
assert.IsNil(err)
|
||||
|
||||
unZipPath := "./unzip"
|
||||
err = UnZip(zipFile, unZipPath)
|
||||
assert.IsNil(err)
|
||||
|
||||
assert.Equal(true, IsExist("./unzip/text.txt"))
|
||||
assert.Equal(true, IsExist("./unzip/file.go"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/file.go.zip"))
|
||||
assert.Equal(true, IsExist("./unzip/testdata/test.txt"))
|
||||
|
||||
os.Remove(srcFile)
|
||||
os.Remove(zipFile)
|
||||
os.RemoveAll(unZipPath)
|
||||
}
|
||||
|
||||
func TestFileMode(t *testing.T) {
|
||||
assert := internal.NewAssert(t, "TestFileMode")
|
||||
|
||||
|
||||
@@ -18,9 +18,11 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"mime/multipart"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
@@ -93,6 +95,7 @@ type HttpRequest struct {
|
||||
Headers http.Header
|
||||
QueryParams url.Values
|
||||
FormData url.Values
|
||||
File *File
|
||||
Body []byte
|
||||
}
|
||||
|
||||
@@ -180,7 +183,11 @@ func (client *HttpClient) SendRequest(request *HttpRequest) (*http.Response, err
|
||||
client.setQueryParam(req, rawUrl, request.QueryParams)
|
||||
|
||||
if request.FormData != nil {
|
||||
client.setFormData(req, request.FormData)
|
||||
if request.File != nil {
|
||||
err = client.setFormData(req, request.FormData, setFile(request.File))
|
||||
} else {
|
||||
err = client.setFormData(req, request.FormData, nil)
|
||||
}
|
||||
}
|
||||
|
||||
client.Request = req
|
||||
@@ -244,10 +251,79 @@ func (client *HttpClient) setQueryParam(req *http.Request, reqUrl string, queryP
|
||||
return nil
|
||||
}
|
||||
|
||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values) {
|
||||
formData := []byte(values.Encode())
|
||||
req.Body = ioutil.NopCloser(bytes.NewReader(formData))
|
||||
req.ContentLength = int64(len(formData))
|
||||
func (client *HttpClient) setFormData(req *http.Request, values url.Values, setFile SetFileFunc) error {
|
||||
if setFile != nil {
|
||||
err := setFile(req, values)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
formData := []byte(values.Encode())
|
||||
req.Body = io.NopCloser(bytes.NewReader(formData))
|
||||
req.ContentLength = int64(len(formData))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type SetFileFunc func(req *http.Request, values url.Values) error
|
||||
|
||||
// File struct is a combination of file attributes
|
||||
type File struct {
|
||||
Content []byte
|
||||
Path string
|
||||
FieldName string
|
||||
FileName string
|
||||
}
|
||||
|
||||
// setFile set parameters for http request formdata file upload
|
||||
func setFile(f *File) SetFileFunc {
|
||||
return func(req *http.Request, values url.Values) error {
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
|
||||
for key, vals := range values {
|
||||
for _, val := range vals {
|
||||
err := writer.WriteField(key, val)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if f.Content != nil {
|
||||
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
part.Write(f.Content)
|
||||
} else if f.Path != "" {
|
||||
file, err := os.Open(f.Path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
part, err := writer.CreateFormFile(f.FieldName, f.FileName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
_, err = io.Copy(part, file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
err := writer.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
req.Body = io.NopCloser(body)
|
||||
req.Header.Set("Content-Type", writer.FormDataContentType())
|
||||
req.ContentLength = int64(body.Len())
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// validateRequest check if a request has url, and valid method.
|
||||
|
||||
@@ -1,12 +1,15 @@
|
||||
package netutil
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"net/url"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/duke-git/lancet/internal"
|
||||
@@ -250,3 +253,108 @@ func TestStructToUrlValues(t *testing.T) {
|
||||
assert.Equal("456", queryValues2.Get("userId"))
|
||||
assert.Equal("", queryValues2.Get("name"))
|
||||
}
|
||||
|
||||
func handleFileRequest(t *testing.T, w http.ResponseWriter, r *http.Request) {
|
||||
err := r.ParseMultipartForm(1024)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
key1 := r.FormValue("key1")
|
||||
expectedKey1 := "value1"
|
||||
if key1 != expectedKey1 {
|
||||
t.Fatalf("expected %s, got %s", expectedKey1, key1)
|
||||
}
|
||||
|
||||
key2 := r.FormValue("key2")
|
||||
expectedKey2 := "value2"
|
||||
if key2 != expectedKey2 {
|
||||
t.Fatalf("expected %s, got %s", expectedKey2, key2)
|
||||
}
|
||||
|
||||
file, header, err := r.FormFile("image")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedFileName := "testImage.jpg"
|
||||
if header.Filename != expectedFileName {
|
||||
t.Fatalf("expected %s, got %s", expectedFileName, header.Filename)
|
||||
}
|
||||
|
||||
defer file.Close()
|
||||
|
||||
content, err := ioutil.ReadAll(file)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
expectedContent := []byte("file content")
|
||||
if !bytes.Equal(content, expectedContent) {
|
||||
t.Fatalf("expected %s, got %s", string(expectedContent), string(content))
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendRequestWithFileContent(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
handleFileRequest(t, writer, request)
|
||||
})
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
client := NewHttpClient()
|
||||
request := &HttpRequest{
|
||||
RawURL: server.URL,
|
||||
Method: "POST",
|
||||
File: &File{Content: []byte("file content"), FieldName: "image", FileName: "testImage.jpg"},
|
||||
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||
}
|
||||
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSendRequestWithFilePath(t *testing.T) {
|
||||
handler := http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
||||
handleFileRequest(t, writer, request)
|
||||
})
|
||||
|
||||
server := httptest.NewServer(handler)
|
||||
defer server.Close()
|
||||
|
||||
tmpFile, err := ioutil.TempFile("", "testImage.jpg")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer os.Remove(tmpFile.Name())
|
||||
|
||||
tmpFile.Write([]byte("file content"))
|
||||
tmpFile.Close()
|
||||
|
||||
client := NewHttpClient()
|
||||
request := &HttpRequest{
|
||||
RawURL: server.URL,
|
||||
Method: "POST",
|
||||
File: &File{Path: tmpFile.Name(), FieldName: "image", FileName: "testImage.jpg"},
|
||||
FormData: url.Values{"key1": {"value1"}, "key2": {"value2"}},
|
||||
}
|
||||
|
||||
resp, err := client.SendRequest(request)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("expected %d, got %d", http.StatusOK, resp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user