Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 470c77cf37 | |||
| 0393e5468f | |||
| f93724f865 | |||
| fdbb29ef15 | |||
| a4d8c8f7f5 | |||
| 4820a881e8 | |||
| 6d4a89b84e | |||
| a17e6d71ba | |||
| 5379d4dfbb | |||
| 027c7539de | |||
| 6192dca562 | |||
| c032b7c3e5 | |||
| 171239d819 | |||
| 4f3624270b | |||
| 8d3b5385f0 | |||
| cf679a8bdd | |||
| 6af7becd53 | |||
| eb3f1e523f | |||
| b59ecf51be | |||
| 39fa3715e4 | |||
| 1a7a3b600b | |||
| 89d6a19474 | |||
| b8dbae11d9 | |||
| 8e3b4252f0 | |||
| bb7ae5fd3e | |||
| c1f8e32399 | |||
| d755295be2 | |||
| b81493c626 | |||
| 2b0e131d00 | |||
| e3922d2afb | |||
| 5ef2fcc54f | |||
| 121efa4413 | |||
| aa99f50b3f | |||
| cb3a42bc23 | |||
| 712238a5c4 | |||
| 07ca3b69ad | |||
| e158cc5dc5 | |||
| b46b464236 | |||
| 636d89faa7 | |||
| c4f78703d7 | |||
| 8a7c8512f8 | |||
| 02f393be3f | |||
| c87ce79386 | |||
| b9ace42a5b | |||
| 3a75a83be1 | |||
| af66437067 | |||
| e0a739a681 | |||
| d9ff2bfbeb | |||
| fc13b6ebee | |||
| 6355725204 | |||
| b6aa048c4a | |||
| 5da4c33a57 | |||
| 2a316b984d | |||
| fa780870a7 | |||
| 9144ca7f27 | |||
| 174725cf27 | |||
| 45df60e197 | |||
| ecd18128a4 | |||
| f16f5b0116 | |||
| 8291a17aca | |||
| 7ad16974b6 | |||
| 8918f7f891 | |||
| 29a23a75ba | |||
| d9c5d0857b | |||
| 852924e5df | |||
| 4c13582572 |
@@ -0,0 +1,11 @@
|
||||
# To get started with Dependabot version updates, you'll need to specify which
|
||||
# package ecosystems to update and where the package manifests are located.
|
||||
# Please see the documentation for all configuration options:
|
||||
# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||
|
||||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "gomod" # See documentation for possible values
|
||||
directory: "/" # Location of package manifests
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
@@ -0,0 +1,38 @@
|
||||
name: Go CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
go: ["1.13", "1.14", "1.15", "1.16", "1.17", "1.18", "1.19", "1.20"]
|
||||
fail-fast: false
|
||||
|
||||
steps:
|
||||
- name: Set up Go 1.x
|
||||
uses: actions/setup-go@v4
|
||||
with:
|
||||
go-version: ${{ matrix.go }}
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Build Darabonba
|
||||
run: go build ./dara
|
||||
- name: Build Tea
|
||||
run: go build ./tea
|
||||
- name: Build Util
|
||||
run: go build ./utils
|
||||
|
||||
- name: Test
|
||||
run: go test -race -coverprofile=coverage.txt -covermode=atomic ./dara/... ./utils/... ./tea/...
|
||||
|
||||
- name: CodeCov
|
||||
run: bash <(curl -s https://codecov.io/bash)
|
||||
+1
-1
@@ -3,4 +3,4 @@ coverage.txt
|
||||
coverage.out
|
||||
.DS_Store
|
||||
.history/
|
||||
go.sum
|
||||
vendor/
|
||||
-24
@@ -1,24 +0,0 @@
|
||||
language: go
|
||||
|
||||
go:
|
||||
- 1.12.x
|
||||
|
||||
branches: # build only on these branches
|
||||
only:
|
||||
- master
|
||||
|
||||
install:
|
||||
- export GO111MODULE=on
|
||||
|
||||
notifications:
|
||||
webhooks: https://oapi.dingtalk.com/robot/send?access_token=096ed387df243a6d60835aadeccc47165f3813bc7cb81cdd0cfeadfd28e3acc1
|
||||
email: false
|
||||
on_success: change
|
||||
on_failure: always
|
||||
|
||||
script:
|
||||
- go mod tidy
|
||||
- go test -race -coverprofile=coverage.txt -covermode=atomic ./tea/... ./utils/...
|
||||
|
||||
after_success:
|
||||
- bash <(curl -s https://codecov.io/bash)
|
||||
@@ -1,8 +1,8 @@
|
||||
all:
|
||||
|
||||
fmt:
|
||||
go fmt ./
|
||||
go fmt ./tea ./dara ./utils
|
||||
|
||||
test:
|
||||
go test -race -coverprofile=coverage.txt -covermode=atomic ./tea ./utils
|
||||
go test -race -coverprofile=coverage.txt -covermode=atomic ./tea ./utils ./dara
|
||||
go tool cover -html=coverage.txt -o coverage.html
|
||||
|
||||
+3
-3
@@ -2,11 +2,11 @@
|
||||
|
||||
<a href="https://badge.fury.io/gh/alibabacloud-go%2Ftea"><img src="https://badge.fury.io/gh/alibabacloud-go%2Ftea.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://codecov.io/gh/alibabacloud-go/tea"><img src="https://codecov.io/gh/alibabacloud-go/tea/branch/master/graph/badge.svg" alt="codecov"></a>
|
||||
<a href="https://travis-ci.org/alibabacloud-go/tea"><img src="https://travis-ci.org/alibabacloud-go/tea.svg?branch=master" alt="Travis Build Status"></a>
|
||||
[](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
|
||||
|
||||
该项目用于支持TEA OpenAPI DSL。它是http请求的底层库.
|
||||
该项目用于支持 Darabonba OpenAPI DSL。它是http请求的底层库.
|
||||
|
||||
## 许可证
|
||||
[Apache-2.0](/LICENSE)
|
||||
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
|
||||
<a href="https://badge.fury.io/gh/alibabacloud-go%2Ftea"><img src="https://badge.fury.io/gh/alibabacloud-go%2Ftea.svg" alt="Latest Stable Version"></a>
|
||||
<a href="https://codecov.io/gh/alibabacloud-go/tea"><img src="https://codecov.io/gh/alibabacloud-go/tea/branch/master/graph/badge.svg" alt="codecov"></a>
|
||||
<a href="https://travis-ci.org/alibabacloud-go/tea"><img src="https://travis-ci.org/alibabacloud-go/tea.svg?branch=master" alt="Travis Build Status"></a>
|
||||
[](https://github.com/alibabacloud-go/tea/actions/workflows/go.yml)
|
||||
|
||||
This project is used for support TEA OpenAPI DSL. It's a low-level library for http request.
|
||||
This project is used for support Darabonba OpenAPI DSL. It's a low-level library for http request.
|
||||
|
||||
## License
|
||||
[Apache-2.0](/LICENSE)
|
||||
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
Copyright (c) 2009-present, Alibaba Cloud All rights reserved.
|
||||
|
||||
+439
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1135
File diff suppressed because it is too large
Load Diff
+1368
File diff suppressed because it is too large
Load Diff
+162
@@ -0,0 +1,162 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Date struct {
|
||||
date time.Time
|
||||
}
|
||||
|
||||
func NewDate(dateInput string) (*Date, error) {
|
||||
var t time.Time
|
||||
var err error
|
||||
// 解析输入时间,如果输入格式不对,返回错误
|
||||
formats := []string{
|
||||
"2006-01-02 15:04:05",
|
||||
"2006-01-02 15:04:05.999999999 -0700 MST",
|
||||
"2006-01-02T15:04:05-07:00",
|
||||
"2006-01-02T15:04:05Z",
|
||||
}
|
||||
|
||||
for _, format := range formats {
|
||||
t, err = time.Parse(format, dateInput)
|
||||
if err == nil {
|
||||
return &Date{date: t}, nil
|
||||
}
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to parse date: %v", dateInput)
|
||||
}
|
||||
|
||||
func (t *Date) Format(layout string) string {
|
||||
|
||||
layout = strings.Replace(layout, "yyyy", "2006", 1)
|
||||
layout = strings.Replace(layout, "MM", "01", 1)
|
||||
layout = strings.Replace(layout, "dd", "02", 1)
|
||||
// layout = strings.Replace(layout, "HH", "15", 1)
|
||||
layout = strings.Replace(layout, "hh", "15", 1)
|
||||
layout = strings.Replace(layout, "mm", "04", 1)
|
||||
layout = strings.Replace(layout, "ss", "05", 1)
|
||||
layout = strings.Replace(layout, "a", "PM", 1)
|
||||
layout = strings.Replace(layout, "EEEE", "Monday", 1)
|
||||
layout = strings.Replace(layout, "E", "Mon", 1)
|
||||
return t.date.Format(layout)
|
||||
}
|
||||
|
||||
func (t *Date) Unix() int64 {
|
||||
return t.date.Unix()
|
||||
}
|
||||
|
||||
func (t *Date) UTC() string {
|
||||
return t.date.UTC().Format("2006-01-02 15:04:05.000000000 -0700 MST")
|
||||
}
|
||||
|
||||
func (t *Date) Sub(amount int, unit string) *Date {
|
||||
var duration time.Duration
|
||||
switch unit {
|
||||
case "second", "seconds":
|
||||
duration = time.Duration(-amount) * time.Second
|
||||
case "minute", "minutes":
|
||||
duration = time.Duration(-amount) * time.Minute
|
||||
case "hour", "hours":
|
||||
duration = time.Duration(-amount) * time.Hour
|
||||
case "day", "days":
|
||||
duration = time.Duration(-amount) * 24 * time.Hour
|
||||
case "week", "weeks":
|
||||
duration = time.Duration(-amount) * 7 * 24 * time.Hour
|
||||
case "month", "months":
|
||||
return &Date{date: t.date.AddDate(0, -amount, 0)}
|
||||
case "year", "years":
|
||||
return &Date{date: t.date.AddDate(-amount, 0, 0)}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
newDate := t.date.Add(duration)
|
||||
return &Date{date: newDate}
|
||||
}
|
||||
|
||||
func (t *Date) Add(amount int, unit string) *Date {
|
||||
var duration time.Duration
|
||||
switch unit {
|
||||
case "second", "seconds":
|
||||
duration = time.Duration(amount) * time.Second
|
||||
case "minute", "minutes":
|
||||
duration = time.Duration(amount) * time.Minute
|
||||
case "hour", "hours":
|
||||
duration = time.Duration(amount) * time.Hour
|
||||
case "day", "days":
|
||||
duration = time.Duration(amount) * 24 * time.Hour
|
||||
case "week", "weeks":
|
||||
duration = time.Duration(amount) * 7 * 24 * time.Hour
|
||||
case "month", "months":
|
||||
return &Date{date: t.date.AddDate(0, amount, 0)}
|
||||
case "year", "years":
|
||||
return &Date{date: t.date.AddDate(amount, 0, 0)}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
|
||||
newDate := t.date.Add(duration)
|
||||
return &Date{date: newDate}
|
||||
}
|
||||
|
||||
func (t *Date) Diff(amount string, diffDate *Date) int64 {
|
||||
switch amount {
|
||||
case "second", "seconds":
|
||||
return int64(t.date.Sub(diffDate.date).Seconds())
|
||||
case "minute", "minutes":
|
||||
return int64(t.date.Sub(diffDate.date).Minutes())
|
||||
case "hour", "hours":
|
||||
return int64(t.date.Sub(diffDate.date).Hours())
|
||||
case "day", "days":
|
||||
return int64(t.date.Sub(diffDate.date).Hours() / 24)
|
||||
case "week", "weeks":
|
||||
return int64(t.date.Sub(diffDate.date).Hours() / (24 * 7))
|
||||
case "month", "months":
|
||||
return int64(diffDate.date.Year()*12 + int(diffDate.date.Month()) - (t.date.Year()*12 + int(t.date.Month())))
|
||||
case "year", "years":
|
||||
return int64(t.date.Year() - diffDate.date.Year())
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Date) Hour() int {
|
||||
return t.date.Hour()
|
||||
}
|
||||
|
||||
func (t *Date) Minute() int {
|
||||
return t.date.Minute()
|
||||
}
|
||||
|
||||
func (t *Date) Second() int {
|
||||
return t.date.Second()
|
||||
}
|
||||
|
||||
func (t *Date) Month() int {
|
||||
return int(t.date.Month())
|
||||
}
|
||||
|
||||
func (t *Date) Year() int {
|
||||
return t.date.Year()
|
||||
}
|
||||
|
||||
func (t *Date) DayOfMonth() int {
|
||||
return t.date.Day()
|
||||
}
|
||||
|
||||
func (t *Date) DayOfWeek() int {
|
||||
weekday := int(t.date.Weekday())
|
||||
if weekday == 0 {
|
||||
return 7 // Sunday
|
||||
}
|
||||
return weekday
|
||||
}
|
||||
|
||||
func (t *Date) WeekOfYear() int {
|
||||
_, week := t.date.ISOWeek()
|
||||
return week
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestConstructWithNow(t *testing.T) {
|
||||
date := &Date{date: time.Now()}
|
||||
currentTime := time.Now()
|
||||
if currentTime.Format("2006-01-02 15:04:05") != date.Format("yyyy-MM-dd hh:mm:ss") {
|
||||
t.Errorf("Expected %v, got %v", currentTime.Format("2006-01-02 15:04:05"), date.Format("yyyy-MM-dd hh:mm:ss"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructWithDateTimeString(t *testing.T) {
|
||||
datetime := "2023-03-01T12:00:00Z" // Use RFC3339 format
|
||||
date, err := NewDate(datetime)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
if datetime != date.Format("yyyy-MM-ddThh:mm:ssZ") {
|
||||
t.Errorf("Expected %v, got %v", datetime, date.Format("yyyy-MM-ddThh:mm:ssZ"))
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructWithWrongType(t *testing.T) {
|
||||
_, err := NewDate("20230301 12:00:00 +0000 UTC")
|
||||
if err == nil {
|
||||
t.Errorf("Expected error, but got nil")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConstructWithUTC(t *testing.T) {
|
||||
datetimeUTC := "2023-03-01T12:00:00Z"
|
||||
dateWithUTC, err := NewDate(datetimeUTC)
|
||||
if err != nil {
|
||||
t.Fatalf("Expected no error, got %v", err)
|
||||
}
|
||||
|
||||
referenceDateTime, _ := time.Parse(time.RFC3339, datetimeUTC)
|
||||
if referenceDateTime.Unix() != dateWithUTC.Unix() {
|
||||
t.Errorf("Expected %v, got %v", referenceDateTime.Unix(), dateWithUTC.Unix())
|
||||
}
|
||||
|
||||
formattedDateTime := dateWithUTC.UTC()
|
||||
expectedFormattedDateTime := referenceDateTime.UTC().Format("2006-01-02 15:04:05.000000000 -0700 MST")
|
||||
if formattedDateTime != expectedFormattedDateTime {
|
||||
t.Errorf("Expected %v, got %v", expectedFormattedDateTime, formattedDateTime)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFormat(t *testing.T) {
|
||||
datetime := "2023-03-01T12:00:00Z"
|
||||
date, _ := NewDate(datetime)
|
||||
expected := "2023-03-01 12:00 PM"
|
||||
if result := date.Format("yyyy-MM-dd hh:mm a"); result != expected {
|
||||
t.Errorf("Expected %v, got %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUTC(t *testing.T) {
|
||||
datetime := "2023-03-01T12:00:00+08:00"
|
||||
date, _ := NewDate(datetime)
|
||||
expected := "2023-03-01 04:00:00.000000000 +0000 UTC"
|
||||
if result := date.UTC(); result != expected {
|
||||
t.Errorf("Expected %v, got %v", expected, result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnix(t *testing.T) {
|
||||
datetime := "1970-01-01T00:00:00Z"
|
||||
date, _ := NewDate(datetime)
|
||||
if result := date.Unix(); result != 0 {
|
||||
t.Errorf("Expected 0, got %v", result)
|
||||
}
|
||||
|
||||
datetime = "2023-12-31T08:00:00+08:00"
|
||||
date, _ = NewDate(datetime)
|
||||
if result := date.Unix(); result != 1703980800 {
|
||||
t.Errorf("Expected 1703980800, got %v", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddSub(t *testing.T) {
|
||||
datetime := "2023-03-01T12:00:00Z"
|
||||
date, _ := NewDate(datetime)
|
||||
date = date.Add(1, "day")
|
||||
expectedDate := time.Date(2023, 3, 2, 12, 0, 0, 0, time.UTC)
|
||||
if date.date != expectedDate {
|
||||
t.Errorf("Expected %v, got %v", expectedDate, date.date)
|
||||
}
|
||||
date = date.Sub(1, "day") // Subtract 1 day
|
||||
expectedDate = time.Date(2023, 3, 1, 12, 0, 0, 0, time.UTC)
|
||||
if date.date != expectedDate {
|
||||
t.Errorf("Expected %v, got %v", expectedDate, date.date)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDiff(t *testing.T) {
|
||||
datetime1 := "2023-03-01T12:00:00Z"
|
||||
datetime2 := "2023-04-01T12:00:00Z"
|
||||
date1, _ := NewDate(datetime1)
|
||||
date2, _ := NewDate(datetime2)
|
||||
diffInSeconds := date1.Diff("seconds", date2)
|
||||
if diffInSeconds != -31*24*60*60 {
|
||||
t.Errorf("Expected %v, got %v", -31*24*60*60, diffInSeconds)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHourMinuteSecond(t *testing.T) {
|
||||
datetime := "2023-03-01T12:34:56Z"
|
||||
date, _ := NewDate(datetime)
|
||||
if result := date.Hour(); result != 12 {
|
||||
t.Errorf("Expected 12, got %d", result)
|
||||
}
|
||||
if result := date.Minute(); result != 34 {
|
||||
t.Errorf("Expected 34, got %d", result)
|
||||
}
|
||||
if result := date.Second(); result != 56 {
|
||||
t.Errorf("Expected 56, got %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMonthYearDay(t *testing.T) {
|
||||
datetime := "2023-03-01T12:00:00Z"
|
||||
date, _ := NewDate(datetime)
|
||||
if result := date.Month(); result != 3 {
|
||||
t.Errorf("Expected 3, got %d", result)
|
||||
}
|
||||
if result := date.Year(); result != 2023 {
|
||||
t.Errorf("Expected 2023, got %d", result)
|
||||
}
|
||||
if result := date.DayOfMonth(); result != 1 {
|
||||
t.Errorf("Expected 1, got %d", result)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDayOfWeekWeekOfYear(t *testing.T) {
|
||||
datetime := "2023-03-01 00:00:00"
|
||||
date, _ := NewDate(datetime)
|
||||
if result := date.DayOfWeek(); result != 3 {
|
||||
t.Errorf("Expected 3, got %d", result)
|
||||
}
|
||||
if result := date.WeekOfYear(); result != 9 {
|
||||
t.Errorf("Expected 9, got %d", result)
|
||||
}
|
||||
|
||||
datetime1 := "2023-12-31T12:00:00Z"
|
||||
date1, _ := NewDate(datetime1)
|
||||
if result := date1.DayOfMonth(); result != 31 {
|
||||
t.Errorf("Expected 31, got %d", result)
|
||||
}
|
||||
if result := date1.DayOfWeek(); result != 7 {
|
||||
t.Errorf("Expected 7, got %d", result)
|
||||
}
|
||||
if result := date1.WeekOfYear(); result != 52 {
|
||||
t.Errorf("Expected 52, got %d", result)
|
||||
}
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"reflect"
|
||||
"strconv"
|
||||
"github.com/alibabacloud-go/tea/tea"
|
||||
)
|
||||
|
||||
type BaseError interface {
|
||||
error
|
||||
GetName() *string
|
||||
GetCode() *string
|
||||
}
|
||||
|
||||
type ResponseError interface {
|
||||
BaseError
|
||||
GetRetryAfter() *int64
|
||||
GetStatusCode() *int
|
||||
GetAccessDeniedDetail() map[string]interface{}
|
||||
GetDescription() *string
|
||||
GetData() map[string]interface{}
|
||||
}
|
||||
|
||||
// SDKError struct is used save error code and message
|
||||
type SDKError struct {
|
||||
BaseError
|
||||
Code *string
|
||||
Name *string
|
||||
StatusCode *int
|
||||
Message *string
|
||||
Data *string
|
||||
Stack *string
|
||||
errMsg *string
|
||||
Description *string
|
||||
AccessDeniedDetail map[string]interface{}
|
||||
}
|
||||
|
||||
// CastError is used for cast type fails
|
||||
type CastError struct {
|
||||
Message *string
|
||||
}
|
||||
|
||||
func TeaSDKError(err error) error {
|
||||
if(err == nil) {
|
||||
return nil
|
||||
}
|
||||
|
||||
if te, ok := err.(*SDKError); ok {
|
||||
return tea.NewSDKError(map[string]interface{}{
|
||||
"code": StringValue(te.Code),
|
||||
"statusCode": IntValue(te.StatusCode),
|
||||
"message": StringValue(te.Message),
|
||||
"data": te.Data,
|
||||
"description": StringValue(te.Description),
|
||||
"accessDeniedDetail": te.AccessDeniedDetail,
|
||||
})
|
||||
}
|
||||
|
||||
if respErr, ok := err.(ResponseError); ok {
|
||||
return tea.NewSDKError(map[string]interface{}{
|
||||
"code": StringValue(respErr.GetCode()),
|
||||
"statusCode": IntValue(respErr.GetStatusCode()),
|
||||
"message": respErr.Error(),
|
||||
"description": StringValue(respErr.GetDescription()),
|
||||
"data": respErr.GetData(),
|
||||
"accessDeniedDetail": respErr.GetAccessDeniedDetail(),
|
||||
})
|
||||
}
|
||||
|
||||
if baseErr, ok := err.(BaseError); ok {
|
||||
return tea.NewSDKError(map[string]interface{}{
|
||||
"code": StringValue(baseErr.GetCode()),
|
||||
"message": baseErr.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// NewSDKError is used for shortly create SDKError object
|
||||
func NewSDKError(obj map[string]interface{}) *SDKError {
|
||||
err := &SDKError{}
|
||||
err.Name = String("BaseError")
|
||||
if val, ok := obj["code"].(int); ok {
|
||||
err.Code = String(strconv.Itoa(val))
|
||||
} else if val, ok := obj["code"].(string); ok {
|
||||
err.Code = String(val)
|
||||
}
|
||||
|
||||
if obj["message"] != nil {
|
||||
err.Message = String(obj["message"].(string))
|
||||
}
|
||||
|
||||
if obj["name"] != nil {
|
||||
|
||||
}
|
||||
|
||||
if obj["description"] != nil {
|
||||
err.Description = String(obj["description"].(string))
|
||||
}
|
||||
if detail := obj["accessDeniedDetail"]; detail != nil {
|
||||
r := reflect.ValueOf(detail)
|
||||
if r.Kind().String() == "map" {
|
||||
res := make(map[string]interface{})
|
||||
tmp := r.MapKeys()
|
||||
for _, key := range tmp {
|
||||
res[key.String()] = r.MapIndex(key).Interface()
|
||||
}
|
||||
err.AccessDeniedDetail = res
|
||||
}
|
||||
}
|
||||
if data := obj["data"]; data != nil {
|
||||
r := reflect.ValueOf(data)
|
||||
if r.Kind().String() == "map" {
|
||||
res := make(map[string]interface{})
|
||||
tmp := r.MapKeys()
|
||||
for _, key := range tmp {
|
||||
res[key.String()] = r.MapIndex(key).Interface()
|
||||
}
|
||||
if statusCode := res["statusCode"]; statusCode != nil {
|
||||
if code, ok := statusCode.(int); ok {
|
||||
err.StatusCode = Int(code)
|
||||
} else if tmp, ok := statusCode.(string); ok {
|
||||
code, err_ := strconv.Atoi(tmp)
|
||||
if err_ == nil {
|
||||
err.StatusCode = Int(code)
|
||||
}
|
||||
} else if code, ok := statusCode.(*int); ok {
|
||||
err.StatusCode = code
|
||||
}
|
||||
}
|
||||
}
|
||||
byt := bytes.NewBuffer([]byte{})
|
||||
jsonEncoder := json.NewEncoder(byt)
|
||||
jsonEncoder.SetEscapeHTML(false)
|
||||
jsonEncoder.Encode(data)
|
||||
err.Data = String(string(bytes.TrimSpace(byt.Bytes())))
|
||||
}
|
||||
|
||||
if statusCode, ok := obj["statusCode"].(int); ok {
|
||||
err.StatusCode = Int(statusCode)
|
||||
} else if status, ok := obj["statusCode"].(string); ok {
|
||||
statusCode, err_ := strconv.Atoi(status)
|
||||
if err_ == nil {
|
||||
err.StatusCode = Int(statusCode)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (err *SDKError) ErrorName() *string {
|
||||
return err.Name
|
||||
}
|
||||
|
||||
func (err *SDKError) ErrorMessage() *string {
|
||||
return err.Message
|
||||
}
|
||||
|
||||
func (err *SDKError) GetCode() *string {
|
||||
return err.Code
|
||||
}
|
||||
|
||||
// Set ErrMsg by msg
|
||||
func (err *SDKError) SetErrMsg(msg string) {
|
||||
err.errMsg = String(msg)
|
||||
}
|
||||
|
||||
func (err *SDKError) Error() string {
|
||||
if err.errMsg == nil {
|
||||
str := fmt.Sprintf("SDKError:\n StatusCode: %d\n Code: %s\n Message: %s\n Data: %s\n",
|
||||
IntValue(err.StatusCode), StringValue(err.Code), StringValue(err.Message), StringValue(err.Data))
|
||||
err.SetErrMsg(str)
|
||||
}
|
||||
return StringValue(err.errMsg)
|
||||
}
|
||||
|
||||
// Return message of CastError
|
||||
func (err *CastError) Error() string {
|
||||
return StringValue(err.Message)
|
||||
}
|
||||
|
||||
func Retryable(err error) *bool {
|
||||
if err == nil {
|
||||
return Bool(false)
|
||||
}
|
||||
if realErr, ok := err.(*SDKError); ok {
|
||||
if realErr.StatusCode == nil {
|
||||
return Bool(false)
|
||||
}
|
||||
code := IntValue(realErr.StatusCode)
|
||||
return Bool(code >= http.StatusInternalServerError)
|
||||
}
|
||||
return Bool(true)
|
||||
}
|
||||
|
||||
// NewCastError is used for cast type fails
|
||||
func NewCastError(message *string) (err error) {
|
||||
return &CastError{
|
||||
Message: message,
|
||||
}
|
||||
}
|
||||
+146
@@ -0,0 +1,146 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
// File struct to represent the file
|
||||
type DaraFile struct {
|
||||
path string
|
||||
fileInfo os.FileInfo
|
||||
file *os.File
|
||||
position int64
|
||||
}
|
||||
|
||||
// NewFile creates a new instance of File
|
||||
func NewDaraFile(path string) *DaraFile {
|
||||
return &DaraFile{
|
||||
path: path,
|
||||
position: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Path returns the path of the file
|
||||
func (tf *DaraFile) Path() string {
|
||||
return tf.path
|
||||
}
|
||||
|
||||
// CreateTime returns the creation time of the file
|
||||
func (tf *DaraFile) CreateTime() (*Date, error) {
|
||||
if tf.fileInfo == nil {
|
||||
var err error
|
||||
tf.fileInfo, err = os.Stat(tf.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Date{tf.fileInfo.ModTime()}, nil
|
||||
}
|
||||
|
||||
// ModifyTime returns the modification time of the file
|
||||
func (tf *DaraFile) ModifyTime() (*Date, error) {
|
||||
if tf.fileInfo == nil {
|
||||
var err error
|
||||
tf.fileInfo, err = os.Stat(tf.path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &Date{tf.fileInfo.ModTime()}, nil
|
||||
}
|
||||
|
||||
// Length returns the size of the file
|
||||
func (tf *DaraFile) Length() (int64, error) {
|
||||
if tf.fileInfo == nil {
|
||||
var err error
|
||||
tf.fileInfo, err = os.Stat(tf.path)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
return tf.fileInfo.Size(), nil
|
||||
}
|
||||
|
||||
// Read reads a specified number of bytes from the file
|
||||
func (tf *DaraFile) Read(size int) ([]byte, error) {
|
||||
if tf.file == nil {
|
||||
file, err := os.OpenFile(tf.path, os.O_RDWR|os.O_CREATE, 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tf.file = file
|
||||
}
|
||||
|
||||
fileInfo, err := tf.file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// 获取文件大小
|
||||
fileSize := fileInfo.Size()
|
||||
|
||||
// 计算可以读取的实际大小
|
||||
if tf.position >= fileSize {
|
||||
return nil, nil // End of file reached
|
||||
}
|
||||
|
||||
// 确保 size 不超过剩余文件大小
|
||||
actualSize := size
|
||||
if tf.position+int64(size) > fileSize {
|
||||
actualSize = int(fileSize - tf.position)
|
||||
}
|
||||
|
||||
buf := make([]byte, actualSize)
|
||||
bytesRead, err := tf.file.ReadAt(buf, tf.position)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tf.position += int64(bytesRead)
|
||||
return buf[:bytesRead], nil
|
||||
}
|
||||
|
||||
// Write writes data to the file
|
||||
func (tf *DaraFile) Write(data []byte) error {
|
||||
if tf.file == nil {
|
||||
file, err := os.OpenFile(tf.path, os.O_RDWR|os.O_CREATE, 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tf.file = file
|
||||
}
|
||||
|
||||
_, err := tf.file.Write(data)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
tf.fileInfo, err = os.Stat(tf.path) // Update fileInfo after write
|
||||
return err
|
||||
}
|
||||
|
||||
// Close closes the file
|
||||
func (tf *DaraFile) Close() error {
|
||||
if tf.file == nil {
|
||||
return nil
|
||||
}
|
||||
return tf.file.Close()
|
||||
}
|
||||
|
||||
// Exists checks if the file exists
|
||||
func Exists(path string) (bool, error) {
|
||||
_, err := os.Stat(path)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return err == nil, err
|
||||
}
|
||||
|
||||
// CreateReadStream would typically return an os.File or similar
|
||||
func CreateReadStream(path string) (*os.File, error) {
|
||||
return os.Open(path)
|
||||
}
|
||||
|
||||
// CreateWriteStream would typically return an os.File or similar
|
||||
func CreateWriteStream(path string) (*os.File, error) {
|
||||
return os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestNewDaraFile tests the NewDaraFile function
|
||||
func TestNewDaraFile(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
tf := NewDaraFile(path)
|
||||
if tf.Path() != path {
|
||||
t.Errorf("Expected path to be %s, got %s", path, tf.Path())
|
||||
}
|
||||
}
|
||||
|
||||
// TestCreateTime tests the CreateTime method
|
||||
func TestCreateTime(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
ioutil.WriteFile(path, []byte("test"), 0644) // 创建文件以确保它存在
|
||||
defer os.Remove(path)
|
||||
|
||||
tf := NewDaraFile(path)
|
||||
date, err := tf.CreateTime()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if date == nil {
|
||||
t.Error("expected a valid TeaDate, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestModifyTime tests the ModifyTime method
|
||||
func TestModifyTime(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
ioutil.WriteFile(path, []byte("test"), 0644)
|
||||
defer os.Remove(path)
|
||||
|
||||
tf := NewDaraFile(path)
|
||||
date, err := tf.ModifyTime()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if date == nil {
|
||||
t.Error("expected a valid TeaDate, got nil")
|
||||
}
|
||||
}
|
||||
|
||||
// TestLength tests the Length method
|
||||
func TestLength(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
content := []byte("Hello, World!")
|
||||
ioutil.WriteFile(path, content, 0644)
|
||||
defer os.Remove(path)
|
||||
|
||||
tf := NewDaraFile(path)
|
||||
length, err := tf.Length()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if length != int64(len(content)) {
|
||||
t.Errorf("expected length %d, got %d", len(content), length)
|
||||
}
|
||||
}
|
||||
|
||||
// TestRead tests the Read method
|
||||
func TestRead(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
content := []byte("Hello, World!")
|
||||
ioutil.WriteFile(path, content, 0644)
|
||||
defer os.Remove(path)
|
||||
|
||||
tf := NewDaraFile(path)
|
||||
data, err := tf.Read(5)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != "Hello" {
|
||||
t.Errorf("expected 'Hello', got '%s'", string(data))
|
||||
}
|
||||
|
||||
// Read the rest of the file
|
||||
data, err = tf.Read(10)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
if string(data) != ", World!" {
|
||||
t.Errorf("expected ', World!', got '%s'", string(data))
|
||||
}
|
||||
}
|
||||
|
||||
// TestWrite tests the Write method
|
||||
func TestWrite(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
tf := NewDaraFile(path)
|
||||
|
||||
data := []byte("Hello, Write Test!")
|
||||
err := tf.Write(data)
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
|
||||
// Validate the content of the file
|
||||
readData, _ := ioutil.ReadFile(path)
|
||||
if string(readData) != "Hello, Write Test!" {
|
||||
t.Errorf("expected file content to be %s, got %s", string(data), string(readData))
|
||||
}
|
||||
}
|
||||
|
||||
// TestClose tests the Close method
|
||||
func TestClose(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
tf := NewDaraFile(path)
|
||||
err := tf.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("unexpected error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestExists tests the Exists function
|
||||
func TestExists(t *testing.T) {
|
||||
path := "testfile.txt"
|
||||
ioutil.WriteFile(path, []byte("test"), 0644)
|
||||
defer os.Remove(path)
|
||||
|
||||
exists, err := Exists(path)
|
||||
if err != nil || !exists {
|
||||
t.Errorf("expected file to exist, got error: %v", err)
|
||||
}
|
||||
|
||||
exists, err = Exists("nonexistent.txt")
|
||||
if err != nil || exists {
|
||||
t.Errorf("expected file to not exist, got error: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCreateReadWriteStream(t *testing.T) {
|
||||
tempDir, err := ioutil.TempDir("", "example")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tempDir)
|
||||
testFile := filepath.Join(tempDir, "test.txt")
|
||||
testWFile := filepath.Join(tempDir, "test2.txt")
|
||||
|
||||
// Prepare the test file
|
||||
originalContent := "Hello, World!"
|
||||
if err := ioutil.WriteFile(testFile, []byte(originalContent), 0644); err != nil {
|
||||
t.Fatalf("failed to write test file: %v", err)
|
||||
}
|
||||
|
||||
// Test CreateReadStream
|
||||
rs, err := CreateReadStream(testFile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create read stream: %v", err)
|
||||
}
|
||||
defer rs.Close()
|
||||
|
||||
// Test CreateWriteStream
|
||||
ws, err := CreateWriteStream(testWFile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to create write stream: %v", err)
|
||||
}
|
||||
defer ws.Close()
|
||||
|
||||
// Pipe data from read stream to write stream
|
||||
if _, err := io.Copy(ws, rs); err != nil {
|
||||
t.Fatalf("failed to copy data from read stream to write stream: %v", err)
|
||||
}
|
||||
|
||||
// Read back the content to check if it's correct
|
||||
data, err := ioutil.ReadFile(testWFile)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read back test file: %v", err)
|
||||
}
|
||||
|
||||
if string(data) != originalContent {
|
||||
t.Fatalf("expected %q but got %q", originalContent, string(data))
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type FileField struct {
|
||||
Filename *string `json:"filename" xml:"filename" require:"true"`
|
||||
ContentType *string `json:"content-type" xml:"content-type" require:"true"`
|
||||
Content io.Reader `json:"content" xml:"content" require:"true"`
|
||||
}
|
||||
|
||||
func (s *FileField) SetFilename(v string) *FileField {
|
||||
s.Filename = &v
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *FileField) SetContentType(v string) *FileField {
|
||||
s.ContentType = &v
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *FileField) SetContent(v io.Reader) *FileField {
|
||||
s.Content = v
|
||||
return s
|
||||
}
|
||||
|
||||
type FileFormReader struct {
|
||||
formFiles []*formFile
|
||||
formField io.Reader
|
||||
index int
|
||||
streaming bool
|
||||
ifField bool
|
||||
}
|
||||
|
||||
type formFile struct {
|
||||
StartField io.Reader
|
||||
EndField io.Reader
|
||||
File io.Reader
|
||||
start bool
|
||||
end bool
|
||||
}
|
||||
|
||||
const numBytes = "1234567890"
|
||||
|
||||
func GetBoundary() string {
|
||||
b := make([]byte, 14)
|
||||
for i := range b {
|
||||
b[i] = numBytes[rand.Intn(len(numBytes))]
|
||||
}
|
||||
return string(b)
|
||||
}
|
||||
|
||||
func ToFileForm(body map[string]interface{}, boundary string) io.Reader {
|
||||
out := bytes.NewBuffer(nil)
|
||||
line := "--" + boundary + "\r\n"
|
||||
forms := make(map[string]string)
|
||||
files := make(map[string]map[string]interface{})
|
||||
for key, value := range body {
|
||||
switch value.(type) {
|
||||
case *FileField:
|
||||
if val, ok := value.(*FileField); ok {
|
||||
out := make(map[string]interface{})
|
||||
out["filename"] = StringValue(val.Filename)
|
||||
out["content-type"] = StringValue(val.ContentType)
|
||||
out["content"] = val.Content
|
||||
files[key] = out
|
||||
}
|
||||
case map[string]interface{}:
|
||||
if val, ok := value.(map[string]interface{}); ok {
|
||||
files[key] = val
|
||||
}
|
||||
default:
|
||||
forms[key] = fmt.Sprintf("%v", value)
|
||||
}
|
||||
}
|
||||
for key, value := range forms {
|
||||
if value != "" {
|
||||
out.Write([]byte(line))
|
||||
out.Write([]byte("Content-Disposition: form-data; name=\"" + key + "\"" + "\r\n\r\n"))
|
||||
out.Write([]byte(value + "\r\n"))
|
||||
}
|
||||
}
|
||||
formFiles := make([]*formFile, 0)
|
||||
for key, value := range files {
|
||||
var file io.Reader
|
||||
start := line
|
||||
start += "Content-Disposition: form-data; name=\"" + key + "\"; filename=\"" + value["filename"].(string) + "\"\r\n"
|
||||
start += "Content-Type: " + value["content-type"].(string) + "\r\n\r\n"
|
||||
if content, ok := value["content"].(io.Reader); ok {
|
||||
file = content
|
||||
} else {
|
||||
file = strings.NewReader("")
|
||||
}
|
||||
formFile := &formFile{
|
||||
File: file,
|
||||
start: true,
|
||||
StartField: strings.NewReader(start),
|
||||
}
|
||||
if len(files) == len(formFiles)+1 {
|
||||
end := "\r\n\r\n--" + boundary + "--\r\n"
|
||||
formFile.EndField = strings.NewReader(end)
|
||||
} else {
|
||||
formFile.EndField = strings.NewReader("\r\n\r\n")
|
||||
}
|
||||
formFiles = append(formFiles, formFile)
|
||||
}
|
||||
return &FileFormReader{
|
||||
formFiles: formFiles,
|
||||
formField: out,
|
||||
ifField: true,
|
||||
}
|
||||
}
|
||||
|
||||
func (f *FileFormReader) Read(p []byte) (n int, err error) {
|
||||
if f.ifField {
|
||||
n, err = f.formField.Read(p)
|
||||
if err != nil && err != io.EOF {
|
||||
return n, err
|
||||
} else if err == io.EOF {
|
||||
err = nil
|
||||
f.ifField = false
|
||||
f.streaming = true
|
||||
}
|
||||
} else if f.streaming {
|
||||
form := f.formFiles[f.index]
|
||||
if form.start {
|
||||
n, err = form.StartField.Read(p)
|
||||
if err != nil && err != io.EOF {
|
||||
return n, err
|
||||
} else if err == io.EOF {
|
||||
err = nil
|
||||
form.start = false
|
||||
}
|
||||
} else if form.end {
|
||||
n, err = form.EndField.Read(p)
|
||||
if err != nil && err != io.EOF {
|
||||
return n, err
|
||||
} else if err == io.EOF {
|
||||
f.index++
|
||||
form.end = false
|
||||
if f.index < len(f.formFiles) {
|
||||
err = nil
|
||||
}
|
||||
}
|
||||
} else {
|
||||
n, err = form.File.Read(p)
|
||||
if err != nil && err != io.EOF {
|
||||
return n, err
|
||||
} else if err == io.EOF {
|
||||
err = nil
|
||||
form.end = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
func ToFormString(a map[string]interface{}) string {
|
||||
if a == nil {
|
||||
return ""
|
||||
}
|
||||
res := ""
|
||||
urlEncoder := url.Values{}
|
||||
for key, value := range a {
|
||||
v := fmt.Sprintf("%v", value)
|
||||
urlEncoder.Add(key, v)
|
||||
}
|
||||
res = urlEncoder.Encode()
|
||||
return res
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/alibabacloud-go/tea/utils"
|
||||
)
|
||||
|
||||
func Test_ToFormString(t *testing.T) {
|
||||
str := ToFormString(nil)
|
||||
utils.AssertEqual(t, "", str)
|
||||
|
||||
a := map[string]interface{}{
|
||||
"key1": "value1",
|
||||
"key2": "value2",
|
||||
}
|
||||
str = ToFormString(a)
|
||||
utils.AssertEqual(t, str, "key1=value1&key2=value2")
|
||||
}
|
||||
|
||||
type TestForm struct {
|
||||
Ak *string `json:"ak"`
|
||||
File1 *FileField `json:"file1"`
|
||||
File2 *FileField `json:"file2"`
|
||||
}
|
||||
|
||||
func Test_ToFileForm(t *testing.T) {
|
||||
file1 := new(FileField).
|
||||
SetContent(strings.NewReader("ok")).
|
||||
SetContentType("jpg").
|
||||
SetFilename("a.jpg")
|
||||
body := map[string]interface{}{
|
||||
"ak": "accesskey",
|
||||
"file1": file1,
|
||||
}
|
||||
res := ToFileForm(ToMap(body), "28802961715230")
|
||||
byt, err := ioutil.ReadAll(res)
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, string(byt), "--28802961715230\r\nContent-Disposition: "+
|
||||
"form-data; name=\"ak\"\r\n\r\naccesskey\r\n--28802961715230\r\nContent-Disposition: "+
|
||||
"form-data; name=\"file1\"; filename=\"a.jpg\"\r\nContent-Type: jpg\r\n\r\nok\r\n\r\n--28802961715230--\r\n")
|
||||
|
||||
body1 := &TestForm{
|
||||
Ak: String("accesskey"),
|
||||
File1: &FileField{
|
||||
Filename: String("a.jpg"),
|
||||
ContentType: String("jpg"),
|
||||
Content: strings.NewReader("ok"),
|
||||
},
|
||||
}
|
||||
res = ToFileForm(ToMap(body1), "28802961715230")
|
||||
byt, err = ioutil.ReadAll(res)
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, string(byt), "--28802961715230\r\nContent-Disposition: form-data; "+
|
||||
"name=\"ak\"\r\n\r\naccesskey\r\n--28802961715230\r\nContent-Disposition: "+
|
||||
"form-data; name=\"file1\"; filename=\"a.jpg\"\r\nContent-Type: jpg\r\n\r\n\r\n\r\n--28802961715230--\r\n")
|
||||
}
|
||||
|
||||
func Test_GetBoundary(t *testing.T) {
|
||||
bound := GetBoundary()
|
||||
utils.AssertEqual(t, len(bound), 14)
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+49
@@ -0,0 +1,49 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
)
|
||||
|
||||
type Entry struct {
|
||||
Key string
|
||||
Value interface{}
|
||||
}
|
||||
|
||||
// toFloat64 converts a numeric value to float64 for comparison
|
||||
func Entries(m interface{}) []*Entry {
|
||||
v := reflect.ValueOf(m)
|
||||
if v.Kind() != reflect.Map {
|
||||
panic("Entries: input must be a map")
|
||||
}
|
||||
|
||||
entries := make([]*Entry, 0, v.Len())
|
||||
for _, key := range v.MapKeys() {
|
||||
// 确保 Key 是字符串类型
|
||||
if key.Kind() != reflect.String {
|
||||
panic("Entries: map keys must be of type string")
|
||||
}
|
||||
|
||||
value := v.MapIndex(key)
|
||||
entries = append(entries, &Entry{
|
||||
Key: key.String(),
|
||||
Value: value.Interface(),
|
||||
})
|
||||
}
|
||||
return entries
|
||||
}
|
||||
|
||||
func KeySet(m interface{}) []string {
|
||||
v := reflect.ValueOf(m)
|
||||
if v.Kind() != reflect.Map {
|
||||
panic("KeySet: input must be a map")
|
||||
}
|
||||
|
||||
keys := make([]string, 0, v.Len())
|
||||
for _, key := range v.MapKeys() {
|
||||
if key.Kind() != reflect.String {
|
||||
panic("KeySet: map keys must be of type string")
|
||||
}
|
||||
keys = append(keys, key.String())
|
||||
}
|
||||
return keys
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func TestEntries(t *testing.T) {
|
||||
// 定义一个包含多种类型的 map
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
testMap := map[string]interface{}{
|
||||
"one": 1,
|
||||
"two": "two",
|
||||
"three": &Person{Name: "Alice", Age: 30},
|
||||
}
|
||||
|
||||
entries := Entries(testMap)
|
||||
|
||||
if len(entries) != 3 {
|
||||
t.Errorf("expected %d entries, got %d", 3, len(entries))
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
if !reflect.DeepEqual(entry.Value, testMap[entry.Key]) {
|
||||
t.Errorf("expected entry %s to be %v, got %v", entry.Key, testMap[entry.Key], entry.Value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestKeySet(t *testing.T) {
|
||||
testMap := map[string]interface{}{
|
||||
"one": 1,
|
||||
"two": "two",
|
||||
"three": &Person{Name: "Alice", Age: 30},
|
||||
}
|
||||
|
||||
keys := KeySet(testMap)
|
||||
str1, str2, str3 := "one", "two", "three"
|
||||
expectedKeys := []*string{&str1, &str2, &str3}
|
||||
|
||||
if len(keys) != len(expectedKeys) {
|
||||
t.Errorf("expected %d keys, got %d", len(expectedKeys), len(keys))
|
||||
}
|
||||
|
||||
for _, key := range keys {
|
||||
if !ArrContains(expectedKeys, key) {
|
||||
t.Errorf("expected key %s to be in the array %v, but not", key, expectedKeys)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Number is an interface that can be implemented by any numeric type
|
||||
type Number interface{}
|
||||
|
||||
// toFloat64 converts a numeric value to float64 for comparison
|
||||
func toFloat64(n Number) float64 {
|
||||
v := reflect.ValueOf(n)
|
||||
switch v.Kind() {
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return float64(v.Int())
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
return float64(v.Uint())
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float()
|
||||
default:
|
||||
panic("unsupported type")
|
||||
}
|
||||
}
|
||||
|
||||
// Floor returns the largest integer less than or equal to the input number as int
|
||||
func Floor(n Number) int {
|
||||
v := toFloat64(n)
|
||||
floorValue := math.Floor(v)
|
||||
return int(floorValue)
|
||||
}
|
||||
|
||||
// Round returns the nearest integer to the input number as int
|
||||
func Round(n Number) int {
|
||||
v := toFloat64(n)
|
||||
roundValue := math.Round(v)
|
||||
return int(roundValue)
|
||||
}
|
||||
|
||||
func Random() float64 {
|
||||
rand.Seed(time.Now().UnixNano())
|
||||
return rand.Float64()
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestRandom tests the Random function to ensure it returns a value in the range [0.0, 1.0)
|
||||
func TestRandom(t *testing.T) {
|
||||
for i := 0; i < 100; i++ {
|
||||
val := Random()
|
||||
if val < 0.0 || val >= 1.0 {
|
||||
t.Errorf("Random() = %v, want [0.0, 1.0)", val)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestFloor tests the Floor function with various numeric inputs
|
||||
func TestFloor(t *testing.T) {
|
||||
tests := []struct {
|
||||
input Number
|
||||
expected int
|
||||
}{
|
||||
{3.7, 3},
|
||||
{-3.7, -4},
|
||||
{0.9, 0},
|
||||
{0.0, 0},
|
||||
{-0.9, -1},
|
||||
{int64(3), 3},
|
||||
{int32(-3), -3},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := Floor(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Floor(%v) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestRound tests the Round function with various numeric inputs
|
||||
func TestRound(t *testing.T) {
|
||||
tests := []struct {
|
||||
input Number
|
||||
expected int
|
||||
}{
|
||||
{3.7, 4},
|
||||
{-3.7, -4},
|
||||
{2.5, 3},
|
||||
{2.4, 2},
|
||||
{-2.5, -3},
|
||||
{0.0, 0},
|
||||
{int64(4), 4},
|
||||
{int32(-4), -4},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
result := Round(tt.input)
|
||||
if result != tt.expected {
|
||||
t.Errorf("Round(%v) = %v, want %v", tt.input, result, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
+280
@@ -0,0 +1,280 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type Model interface {
|
||||
Validate() error
|
||||
ToMap() map[string]interface{}
|
||||
copyWithouStream() Model
|
||||
}
|
||||
|
||||
func Validate(params interface{}) error {
|
||||
if params == nil {
|
||||
return nil
|
||||
}
|
||||
requestValue := reflect.ValueOf(params)
|
||||
if requestValue.IsNil() {
|
||||
return nil
|
||||
}
|
||||
err := validate(requestValue.Elem())
|
||||
return err
|
||||
}
|
||||
|
||||
// Verify whether the parameters meet the requirements
|
||||
func validate(dataValue reflect.Value) error {
|
||||
if strings.HasPrefix(dataValue.Type().String(), "*") { // Determines whether the input is a structure object or a pointer object
|
||||
if dataValue.IsNil() {
|
||||
return nil
|
||||
}
|
||||
dataValue = dataValue.Elem()
|
||||
}
|
||||
dataType := dataValue.Type()
|
||||
for i := 0; i < dataType.NumField(); i++ {
|
||||
field := dataType.Field(i)
|
||||
valueField := dataValue.Field(i)
|
||||
for _, value := range validateParams {
|
||||
err := validateParam(field, valueField, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateParam(field reflect.StructField, valueField reflect.Value, tagName string) error {
|
||||
tag, containsTag := field.Tag.Lookup(tagName) // Take out the checked regular expression
|
||||
if containsTag && tagName == "require" {
|
||||
err := checkRequire(field, valueField)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if strings.HasPrefix(field.Type.String(), "[]") { // Verify the parameters of the array type
|
||||
err := validateSlice(field, valueField, containsTag, tag, tagName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if valueField.Kind() == reflect.Ptr { // Determines whether it is a pointer object
|
||||
err := validatePtr(field, valueField, containsTag, tag, tagName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validateSlice(field reflect.StructField, valueField reflect.Value, containsregexpTag bool, tag, tagName string) error {
|
||||
if valueField.IsValid() && !valueField.IsNil() { // Determines whether the parameter has a value
|
||||
if containsregexpTag {
|
||||
if tagName == "maxItems" {
|
||||
err := checkMaxItems(field, valueField, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tagName == "minItems" {
|
||||
err := checkMinItems(field, valueField, tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for m := 0; m < valueField.Len(); m++ {
|
||||
elementValue := valueField.Index(m)
|
||||
if elementValue.Type().Kind() == reflect.Ptr { // Determines whether the child elements of an array are of a basic type
|
||||
err := validatePtr(field, elementValue, containsregexpTag, tag, tagName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func validatePtr(field reflect.StructField, elementValue reflect.Value, containsregexpTag bool, tag, tagName string) error {
|
||||
if elementValue.IsNil() {
|
||||
return nil
|
||||
}
|
||||
if isFilterType(elementValue.Elem().Type().String(), basicTypes) {
|
||||
if containsregexpTag {
|
||||
if tagName == "pattern" {
|
||||
err := checkPattern(field, elementValue.Elem(), tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tagName == "maxLength" {
|
||||
err := checkMaxLength(field, elementValue.Elem(), tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tagName == "minLength" {
|
||||
err := checkMinLength(field, elementValue.Elem(), tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tagName == "maximum" {
|
||||
err := checkMaximum(field, elementValue.Elem(), tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if tagName == "minimum" {
|
||||
err := checkMinimum(field, elementValue.Elem(), tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
err := validate(elementValue)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkRequire(field reflect.StructField, valueField reflect.Value) error {
|
||||
name, _ := field.Tag.Lookup("json")
|
||||
strs := strings.Split(name, ",")
|
||||
name = strs[0]
|
||||
if !valueField.IsNil() && valueField.IsValid() {
|
||||
return nil
|
||||
}
|
||||
return errors.New(name + " should be setted")
|
||||
}
|
||||
|
||||
func checkPattern(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() && valueField.String() != "" {
|
||||
value := valueField.String()
|
||||
r, _ := regexp.Compile("^" + tag + "$")
|
||||
if match := r.MatchString(value); !match { // Determines whether the parameter value satisfies the regular expression or not, and throws an error
|
||||
return errors.New(value + " is not matched " + tag)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMaxItems(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() && valueField.String() != "" {
|
||||
maxItems, err := strconv.Atoi(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
length := valueField.Len()
|
||||
if maxItems < length {
|
||||
errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxItems)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMinItems(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() {
|
||||
minItems, err := strconv.Atoi(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
length := valueField.Len()
|
||||
if minItems > length {
|
||||
errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minItems)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMaxLength(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() && valueField.String() != "" {
|
||||
maxLength, err := strconv.Atoi(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
length := valueField.Len()
|
||||
if valueField.Kind().String() == "string" {
|
||||
length = strings.Count(valueField.String(), "") - 1
|
||||
}
|
||||
if maxLength < length {
|
||||
errMsg := fmt.Sprintf("The length of %s is %d which is more than %d", field.Name, length, maxLength)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMinLength(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() {
|
||||
minLength, err := strconv.Atoi(tag)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
length := valueField.Len()
|
||||
if valueField.Kind().String() == "string" {
|
||||
length = strings.Count(valueField.String(), "") - 1
|
||||
}
|
||||
if minLength > length {
|
||||
errMsg := fmt.Sprintf("The length of %s is %d which is less than %d", field.Name, length, minLength)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMaximum(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() && valueField.String() != "" {
|
||||
maximum, err := strconv.ParseFloat(tag, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
byt, _ := json.Marshal(valueField.Interface())
|
||||
num, err := strconv.ParseFloat(string(byt), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if maximum < num {
|
||||
errMsg := fmt.Sprintf("The size of %s is %f which is greater than %f", field.Name, num, maximum)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkMinimum(field reflect.StructField, valueField reflect.Value, tag string) error {
|
||||
if valueField.IsValid() && valueField.String() != "" {
|
||||
minimum, err := strconv.ParseFloat(tag, 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
byt, _ := json.Marshal(valueField.Interface())
|
||||
num, err := strconv.ParseFloat(string(byt), 64)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if minimum > num {
|
||||
errMsg := fmt.Sprintf("The size of %s is %f which is less than %f", field.Name, num, minimum)
|
||||
return errors.New(errMsg)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
+373
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+138
@@ -0,0 +1,138 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// 定义 Event 结构体
|
||||
type SSEEvent struct {
|
||||
ID *string
|
||||
Event *string
|
||||
Data *string
|
||||
Retry *int
|
||||
}
|
||||
|
||||
// 解析单个事件
|
||||
func parseEvent(lines []string) *SSEEvent {
|
||||
event := &SSEEvent{}
|
||||
for _, line := range lines {
|
||||
if strings.HasPrefix(line, "data:") {
|
||||
data := strings.TrimPrefix(line, "data:") + "\n"
|
||||
if event.Data == nil {
|
||||
event.Data = new(string)
|
||||
}
|
||||
*event.Data += data
|
||||
} else if strings.HasPrefix(line, "event:") {
|
||||
eventName := strings.TrimPrefix(line, "event:")
|
||||
event.Event = &eventName
|
||||
} else if strings.HasPrefix(line, "id:") {
|
||||
id := strings.TrimPrefix(line, "id:")
|
||||
event.ID = &id
|
||||
} else if strings.HasPrefix(line, "retry:") {
|
||||
var retry int
|
||||
fmt.Sscanf(strings.TrimPrefix(line, "retry:"), "%d", &retry)
|
||||
event.Retry = &retry
|
||||
}
|
||||
}
|
||||
// Remove last newline from data
|
||||
if event.Data != nil {
|
||||
data := strings.TrimRight(*event.Data, "\n")
|
||||
event.Data = &data
|
||||
}
|
||||
|
||||
return event
|
||||
}
|
||||
|
||||
func ReadAsBytes(body io.Reader) ([]byte, error) {
|
||||
byt, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
r, ok := body.(io.ReadCloser)
|
||||
if ok {
|
||||
r.Close()
|
||||
}
|
||||
return byt, nil
|
||||
}
|
||||
|
||||
func ReadAsJSON(body io.Reader) (result interface{}, err error) {
|
||||
byt, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
if string(byt) == "" {
|
||||
return
|
||||
}
|
||||
r, ok := body.(io.ReadCloser)
|
||||
if ok {
|
||||
r.Close()
|
||||
}
|
||||
d := json.NewDecoder(bytes.NewReader(byt))
|
||||
d.UseNumber()
|
||||
err = d.Decode(&result)
|
||||
return
|
||||
}
|
||||
|
||||
func ReadAsString(body io.Reader) (string, error) {
|
||||
byt, err := ioutil.ReadAll(body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
r, ok := body.(io.ReadCloser)
|
||||
if ok {
|
||||
r.Close()
|
||||
}
|
||||
return string(byt), nil
|
||||
}
|
||||
|
||||
func ReadAsSSE(body io.ReadCloser, eventChannel chan *SSEEvent, errorChannel chan error) {
|
||||
|
||||
go func() {
|
||||
defer func() {
|
||||
body.Close()
|
||||
close(eventChannel)
|
||||
}()
|
||||
|
||||
reader := bufio.NewReader(body)
|
||||
var eventLines []string
|
||||
|
||||
for {
|
||||
line, err := reader.ReadString('\n')
|
||||
if err != nil {
|
||||
if err == io.EOF {
|
||||
// Handle the end of the stream and possibly pending event
|
||||
if len(eventLines) > 0 {
|
||||
event := parseEvent(eventLines)
|
||||
eventChannel <- event
|
||||
}
|
||||
errorChannel <- nil
|
||||
return
|
||||
}
|
||||
errorChannel <- err
|
||||
return
|
||||
}
|
||||
|
||||
line = strings.TrimRight(line, "\n")
|
||||
|
||||
if line == "" {
|
||||
// End of an SSE event
|
||||
if len(eventLines) > 0 {
|
||||
event := parseEvent(eventLines)
|
||||
eventChannel <- event
|
||||
eventLines = []string{} // Reset for the next event
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
eventLines = append(eventLines, line)
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package dara
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"github.com/alibabacloud-go/tea/utils"
|
||||
)
|
||||
|
||||
func Test_ReadAsBytes(t *testing.T) {
|
||||
byt, err := ReadAsBytes(strings.NewReader("common"))
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "common", string(byt))
|
||||
|
||||
byt, err = ReadAsBytes(ioutil.NopCloser(strings.NewReader("common")))
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "common", string(byt))
|
||||
}
|
||||
|
||||
func Test_ReadAsJSON(t *testing.T) {
|
||||
result, err := ReadAsJSON(strings.NewReader(`{"cleint":"test"}`))
|
||||
if res, ok := result.(map[string]interface{}); ok {
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "test", res["cleint"])
|
||||
}
|
||||
|
||||
result, err = ReadAsJSON(strings.NewReader(""))
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertNil(t, result)
|
||||
|
||||
result, err = ReadAsJSON(ioutil.NopCloser(strings.NewReader(`{"cleint":"test"}`)))
|
||||
if res, ok := result.(map[string]interface{}); ok {
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "test", res["cleint"])
|
||||
}
|
||||
}
|
||||
|
||||
func Test_ReadAsString(t *testing.T) {
|
||||
str, err := ReadAsString(strings.NewReader("common"))
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "common", str)
|
||||
|
||||
str, err = ReadAsString(ioutil.NopCloser(strings.NewReader("common")))
|
||||
utils.AssertNil(t, err)
|
||||
utils.AssertEqual(t, "common", str)
|
||||
}
|
||||
+491
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user