mirror of
https://github.com/ggicci/httpin.git
synced 2024-12-02 09:01:33 +02:00
refactor: introduce goconvey for testing
This commit is contained in:
parent
994da584db
commit
7f785a0750
9
directives.go
Normal file
9
directives.go
Normal file
@ -0,0 +1,9 @@
|
||||
package httpin
|
||||
|
||||
type Directive struct {
|
||||
Key string // e.g. query.page, header.x-api-token
|
||||
}
|
||||
|
||||
func BuildDirective(key string) (*Directive, error) {
|
||||
return &Directive{Key: key}, nil
|
||||
}
|
2
go.mod
2
go.mod
@ -1,3 +1,5 @@
|
||||
module github.com/ggicci/httpin
|
||||
|
||||
go 1.16
|
||||
|
||||
require github.com/smartystreets/goconvey v1.6.4 // indirect
|
||||
|
14
go.sum
Normal file
14
go.sum
Normal file
@ -0,0 +1,14 @@
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykElWQ6/NYmHa3jpm/yHnI4xSofP+UP6SpjHcSeM=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384 h1:TFlARGu6Czu1z7q93HTxcP1P+/ZFC/IKythI5RzrnRg=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
@ -6,6 +6,9 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
type JSON struct{}
|
||||
type XML struct{}
|
||||
|
||||
func New(inputStruct interface{}) Middleware {
|
||||
engine, err := NewEngine(inputStruct)
|
||||
if err != nil {
|
||||
|
4
kv.go
4
kv.go
@ -69,6 +69,10 @@ func isTimeType(typ reflect.Type) bool {
|
||||
return typ == timeType
|
||||
}
|
||||
|
||||
func isArrayType(typ reflect.Type) bool {
|
||||
return typ.Kind() == reflect.Array || typ.Kind() == reflect.Slice
|
||||
}
|
||||
|
||||
func setField(fv reflect.Value, formValue []string) error {
|
||||
if len(formValue) == 0 {
|
||||
// TODO(ggicci): throw an error if decorator like "required" set?
|
||||
|
81
kv_test.go
81
kv_test.go
@ -12,48 +12,61 @@ import (
|
||||
)
|
||||
|
||||
type Pagination struct {
|
||||
Page int `query:"page"`
|
||||
PerPage int `query:"per_page"`
|
||||
Page int `in:"query.page"`
|
||||
PerPage int `in:"query.per_page"`
|
||||
}
|
||||
|
||||
type Authorization struct {
|
||||
AccessToken string `in:"query.access_token,header.x-api-token"`
|
||||
}
|
||||
|
||||
// ChaosQuery is designed to make the normal case test coverage higher.
|
||||
type ChaosQuery struct {
|
||||
// Basic Types
|
||||
BoolValue bool `query:"bool"`
|
||||
IntValue int `query:"int"`
|
||||
Int8Value int8 `query:"int8"`
|
||||
Int16Value int16 `query:"int16"`
|
||||
Int32Value int32 `query:"int32"`
|
||||
Int64Value int64 `query:"int64"`
|
||||
UintValue uint `query:"uint"`
|
||||
Uint8Value uint8 `query:"uint8"`
|
||||
Uint16Value uint16 `query:"uint16"`
|
||||
Uint32Value uint32 `query:"uint32"`
|
||||
Uint64Value uint64 `query:"uint64"`
|
||||
Float32Value float32 `query:"float32"`
|
||||
Float64Value float64 `query:"float64"`
|
||||
Complex64Value complex64 `query:"complex64"`
|
||||
Complex128Value complex128 `query:"complex128"`
|
||||
StringValue string `query:"string"`
|
||||
BoolValue bool `in:"query.bool"`
|
||||
IntValue int `in:"query.int"`
|
||||
Int8Value int8 `in:"query.int8"`
|
||||
Int16Value int16 `in:"query.int16"`
|
||||
Int32Value int32 `in:"query.int32"`
|
||||
Int64Value int64 `in:"query.int64"`
|
||||
UintValue uint `in:"query.uint"`
|
||||
Uint8Value uint8 `in:"query.uint8"`
|
||||
Uint16Value uint16 `in:"query.uint16"`
|
||||
Uint32Value uint32 `in:"query.uint32"`
|
||||
Uint64Value uint64 `in:"query.uint64"`
|
||||
Float32Value float32 `in:"query.float32"`
|
||||
Float64Value float64 `in:"query.float64"`
|
||||
Complex64Value complex64 `in:"query.complex64"`
|
||||
Complex128Value complex128 `in:"query.complex128"`
|
||||
StringValue string `in:"query.string"`
|
||||
|
||||
// Time Type
|
||||
TimeValue time.Time `query:"time"`
|
||||
TimeValue time.Time `in:"query.time"`
|
||||
|
||||
// Array
|
||||
BoolList []bool `query:"bools"`
|
||||
IntList []int `query:"ints"`
|
||||
FloatList []float64 `query:"floats"`
|
||||
StringList []string `query:"strings"`
|
||||
TimeList []time.Time `query:"times"`
|
||||
BoolList []bool `in:"query.bools"`
|
||||
IntList []int `in:"query.ints"`
|
||||
FloatList []float64 `in:"query.floats"`
|
||||
StringList []string `in:"query.strings"`
|
||||
TimeList []time.Time `in:"query.times"`
|
||||
}
|
||||
|
||||
type ProductLocation struct {
|
||||
Area string `json:"area" xml:"area"`
|
||||
Floor int `json:"fl" xml:"fl"`
|
||||
Number int `json:"no" xml:"no"`
|
||||
}
|
||||
|
||||
type ProductQuery struct {
|
||||
CreatedAt time.Time `query:"created_at"`
|
||||
Color string `query:"color"`
|
||||
IsSoldout bool `query:"is_soldout"`
|
||||
SortBy []string `query:"sort_by"`
|
||||
SortDesc []bool `query:"sort_desc"`
|
||||
CreatedAt time.Time `in:"query.created_at,required"`
|
||||
Color string `in:"query.color"`
|
||||
IsSoldout bool `in:"query.is_soldout"`
|
||||
SortBy []string `in:"query.sort_by"`
|
||||
SortDesc []bool `in:"query.sort_desc"`
|
||||
Authorization
|
||||
Pagination
|
||||
|
||||
Locations []ProductLocation `in:"body,json"`
|
||||
}
|
||||
|
||||
type ObjectID struct {
|
||||
@ -64,13 +77,13 @@ type ObjectID struct {
|
||||
}
|
||||
|
||||
type Cursor struct {
|
||||
AfterMarker ObjectID `query:"after"`
|
||||
BeforeMarker ObjectID `query:"before"`
|
||||
Limit int `query:"limit"`
|
||||
AfterMarker ObjectID `in:"query.after"`
|
||||
BeforeMarker ObjectID `in:"query.before"`
|
||||
Limit int `in:"query.limit"`
|
||||
}
|
||||
|
||||
type MessageQuery struct {
|
||||
UserId string `query:"uid"`
|
||||
UserId string `in:"query.uid"`
|
||||
Cursor
|
||||
}
|
||||
|
||||
@ -80,7 +93,7 @@ type PositionXY struct {
|
||||
}
|
||||
|
||||
type PointsQuery struct {
|
||||
Positions []PositionXY `query:"positions"`
|
||||
Positions []PositionXY `in:"query.positions"`
|
||||
}
|
||||
|
||||
func TestKV_NormalCase(t *testing.T) {
|
||||
|
9
patch_test.go
Normal file
9
patch_test.go
Normal file
@ -0,0 +1,9 @@
|
||||
package httpin_test
|
||||
|
||||
import "github.com/ggicci/httpin"
|
||||
|
||||
type ProductPatch struct {
|
||||
Title httpin.String `json:"title"`
|
||||
Color httpin.String `json:"color"`
|
||||
Quantity httpin.Int `json:"quantity"`
|
||||
}
|
100
resolver.go
100
resolver.go
@ -1,7 +1,7 @@
|
||||
package httpin
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
@ -11,62 +11,51 @@ type Resolver interface {
|
||||
Resolve([]byte) interface{}
|
||||
}
|
||||
|
||||
type ResolverContext struct {
|
||||
Source string // e.g. query, header, body
|
||||
Key string // e.g. page, x-api-token
|
||||
resolver Resolver
|
||||
}
|
||||
|
||||
type TypeResolver struct {
|
||||
type FieldResolver struct {
|
||||
Type reflect.Type
|
||||
Field reflect.StructField
|
||||
Resolvers []ResolverContext
|
||||
Path []string
|
||||
Fields []TypeResolver
|
||||
Directives []*Directive
|
||||
Fields []*FieldResolver
|
||||
}
|
||||
|
||||
func (r *TypeResolver) IsRoot() bool {
|
||||
func (r *FieldResolver) IsRoot() bool {
|
||||
return r.Field.Name == ""
|
||||
}
|
||||
|
||||
func BuildTypeResolver(t reflect.Type) (TypeResolver, error) {
|
||||
return buildTypeResolver(t)
|
||||
// BuildFieldResolver builds a resolver for the specified struct type.
|
||||
// Which helps resolving fields data from input sources.
|
||||
func BuildFieldResolver(t reflect.Type) (*FieldResolver, error) {
|
||||
if t.Kind() != reflect.Struct {
|
||||
return nil, errors.New("input type must be struct")
|
||||
}
|
||||
|
||||
func (r *TypeResolver) dump(buffer *bytes.Buffer, indent int) {
|
||||
// indent
|
||||
buffer.WriteString(fmt.Sprintf("%s-", strings.Repeat(" ", indent)))
|
||||
|
||||
// field name
|
||||
if !r.IsRoot() {
|
||||
buffer.WriteString(" [" + r.Field.Name + "]")
|
||||
root := &FieldResolver{Type: t}
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
fieldResolver, err := buildFieldResolver(root, t.Field(i))
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
root.Fields = append(root.Fields, fieldResolver)
|
||||
}
|
||||
|
||||
// type
|
||||
buffer.WriteString(" " + r.Type.String())
|
||||
buffer.WriteString(fmt.Sprintf(" (%d)", len(r.Fields)))
|
||||
buffer.WriteString("\n")
|
||||
|
||||
for _, field := range r.Fields {
|
||||
field.dump(buffer, indent+4)
|
||||
}
|
||||
return root, nil
|
||||
}
|
||||
|
||||
func (t *TypeResolver) DumpTree() string {
|
||||
var buffer bytes.Buffer
|
||||
buffer.WriteString("\n")
|
||||
t.dump(&buffer, 0)
|
||||
return string(buffer.Bytes())
|
||||
}
|
||||
|
||||
func buildTypeResolver(t reflect.Type) (TypeResolver, error) {
|
||||
root := TypeResolver{
|
||||
func buildFieldResolver(parent *FieldResolver, field reflect.StructField) (*FieldResolver, error) {
|
||||
t := field.Type
|
||||
root := &FieldResolver{
|
||||
Type: t,
|
||||
Field: reflect.StructField{},
|
||||
Resolvers: nil,
|
||||
Path: []string{},
|
||||
Fields: make([]TypeResolver, 0),
|
||||
Field: field,
|
||||
Path: make([]string, len(parent.Path)+1),
|
||||
}
|
||||
copy(root.Path, parent.Path)
|
||||
root.Path[len(root.Path)-1] = field.Name
|
||||
directives, err := parseStructTag(field)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse struct tag error: %w", err)
|
||||
}
|
||||
root.Directives = directives
|
||||
|
||||
if isBasicType(t) {
|
||||
return root, nil
|
||||
@ -76,15 +65,17 @@ func buildTypeResolver(t reflect.Type) (TypeResolver, error) {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
if isArrayType(t) {
|
||||
return root, nil
|
||||
}
|
||||
|
||||
if t.Kind() == reflect.Struct {
|
||||
for i := 0; i < t.NumField(); i++ {
|
||||
field := t.Field(i)
|
||||
child, err := buildTypeResolver(field.Type)
|
||||
fieldResolver, err := buildFieldResolver(root, t.Field(i))
|
||||
if err != nil {
|
||||
return root, err
|
||||
}
|
||||
child.Field = field
|
||||
root.Fields = append(root.Fields, child)
|
||||
root.Fields = append(root.Fields, fieldResolver)
|
||||
}
|
||||
|
||||
return root, nil
|
||||
@ -92,3 +83,22 @@ func buildTypeResolver(t reflect.Type) (TypeResolver, error) {
|
||||
|
||||
return root, UnsupportedTypeError{Type: t}
|
||||
}
|
||||
|
||||
func parseStructTag(field reflect.StructField) ([]*Directive, error) {
|
||||
directives := make([]*Directive, 0)
|
||||
// Parse and build resolvers from field struct tag. Tag examples:
|
||||
// "query.name"
|
||||
// "query.access_token,header.x-api-token"
|
||||
inTag := field.Tag.Get("in")
|
||||
if inTag == "" {
|
||||
return directives, nil // skip
|
||||
}
|
||||
for _, key := range strings.Split(inTag, ",") {
|
||||
directive, err := BuildDirective(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
directives = append(directives, directive)
|
||||
}
|
||||
return directives, nil
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package httpin_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"reflect"
|
||||
"testing"
|
||||
|
||||
@ -8,15 +9,11 @@ import (
|
||||
)
|
||||
|
||||
func TestResolver_Build(t *testing.T) {
|
||||
resolver, err := httpin.BuildTypeResolver(reflect.TypeOf(ProductQuery{}))
|
||||
resolver, err := httpin.BuildFieldResolver(reflect.TypeOf(ProductQuery{}))
|
||||
if err != nil {
|
||||
t.Error("build type resolver failed")
|
||||
t.Error("build resolver failed:", err)
|
||||
t.Fail()
|
||||
}
|
||||
debug := resolver.DumpTree()
|
||||
if len(debug) == 0 {
|
||||
t.Error("empty tree")
|
||||
t.Fail()
|
||||
}
|
||||
t.Log(debug)
|
||||
jsonContent, _ := json.Marshal(resolver)
|
||||
t.Log(string(jsonContent))
|
||||
}
|
||||
|
277
types.go
277
types.go
@ -1,173 +1,448 @@
|
||||
package httpin
|
||||
|
||||
import "time"
|
||||
import (
|
||||
"encoding/json"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Bool struct {
|
||||
Value bool
|
||||
Valid bool // Valid is true if the corresponding key were found in the source
|
||||
}
|
||||
|
||||
func (t Bool) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Bool) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int struct {
|
||||
Value int
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int8 struct {
|
||||
Value int8
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int8) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int8) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int16 struct {
|
||||
Value int16
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int16) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int16) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int32 struct {
|
||||
Value int32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int32) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int64 struct {
|
||||
Value int64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int64) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint struct {
|
||||
Value uint
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint8 struct {
|
||||
Value uint8
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint8) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint8) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint16 struct {
|
||||
Value uint16
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint16) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint16) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint32 struct {
|
||||
Value uint32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint32) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint64 struct {
|
||||
Value uint64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint64) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Float32 struct {
|
||||
Value float32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Float32) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Float32) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Float64 struct {
|
||||
Value float64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Float64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Float64) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Complex64 struct {
|
||||
Value complex64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Complex64) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Complex64) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Complex128 struct {
|
||||
Value complex128
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Complex128) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Complex128) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type String struct {
|
||||
Value string
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t String) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *String) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Time struct {
|
||||
Value time.Time
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Time) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Time) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type BoolArray struct {
|
||||
Value []bool
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t BoolArray) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *BoolArray) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type IntArray struct {
|
||||
Value []int
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t IntArray) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *IntArray) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int8Array struct {
|
||||
Value []int8
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int8Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int8Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int16Array struct {
|
||||
Value []int16
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int16Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int16Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int32Array struct {
|
||||
Value []int32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int32Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int32Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Int64Array struct {
|
||||
Value []int64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Int64Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Int64Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type UintArray struct {
|
||||
Value []uint
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t UintArray) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *UintArray) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint8Array struct {
|
||||
Value []uint8
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint8Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint8Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint16Array struct {
|
||||
Value []uint16
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint16Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint16Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint32Array struct {
|
||||
Value []uint32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint32Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint32Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Uint64Array struct {
|
||||
Value []uint64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Uint64Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Uint64Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Float32Array struct {
|
||||
Value []float32
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Float32Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Float32Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Float64Array struct {
|
||||
Value []float64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Float64Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Float64Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Complex64Array struct {
|
||||
Value []complex64
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Complex64Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Complex64Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type Complex128Array struct {
|
||||
Value []complex128
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t Complex128Array) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *Complex128Array) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type StringArray struct {
|
||||
Value []string
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t StringArray) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *StringArray) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
||||
type TimeArray struct {
|
||||
Value []time.Time
|
||||
Valid bool
|
||||
}
|
||||
|
||||
func (t TimeArray) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(t.Value)
|
||||
}
|
||||
|
||||
func (t *TimeArray) UnmarshalJSON(data []byte) error {
|
||||
return json.Unmarshal(data, &t.Value)
|
||||
}
|
||||
|
122
types_test.go
Normal file
122
types_test.go
Normal file
@ -0,0 +1,122 @@
|
||||
package httpin_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/ggicci/httpin"
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func TestTypes_Bool(t *testing.T) {
|
||||
var v httpin.Bool
|
||||
|
||||
Convey("Marshal Bool", t, func() {
|
||||
So(json.Unmarshal([]byte("true"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldBeTrue)
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal Bool", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("true"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_Int(t *testing.T) {
|
||||
var v httpin.Int
|
||||
|
||||
Convey("Marshal Int", t, func() {
|
||||
So(json.Unmarshal([]byte("2015"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldEqual, 2015)
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal Int", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("2015"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_Uint(t *testing.T) {
|
||||
var v httpin.Uint
|
||||
|
||||
Convey("Marshal Int", t, func() {
|
||||
So(json.Unmarshal([]byte("2045"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldEqual, 2045)
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal Int", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("2045"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_Float32(t *testing.T) {
|
||||
var v httpin.Float32
|
||||
|
||||
Convey("Marshal Float32", t, func() {
|
||||
So(json.Unmarshal([]byte("3.1415"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldEqual, 3.1415)
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal Float32", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("3.1415"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_Time(t *testing.T) {
|
||||
var v httpin.Time
|
||||
|
||||
Convey("Marshal Time", t, func() {
|
||||
So(json.Unmarshal([]byte("1991-11-10T08:00:00+08:00"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldEqual, time.Date(1991, 11, 10, 8, 0, 0, 0, time.FixedZone("E8", 8*3600)))
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal Time", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("1991-11-10T08:00:00+08:00"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_BoolArray(t *testing.T) {
|
||||
var v httpin.BoolArray
|
||||
|
||||
Convey("Marshal BoolArray", t, func() {
|
||||
So(json.Unmarshal([]byte("[true, false, true]"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldResemble, []bool{true, false, true})
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal BoolArray", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("[true,false,true]"))
|
||||
})
|
||||
}
|
||||
|
||||
func TestTypes_IntArray(t *testing.T) {
|
||||
var v httpin.IntArray
|
||||
|
||||
Convey("Marshal IntArray", t, func() {
|
||||
So(json.Unmarshal([]byte("[9, 12, 1024]"), &v), ShouldBeNil)
|
||||
So(v.Value, ShouldResemble, []int{9, 12, 1024})
|
||||
So(v.Valid, ShouldBeFalse)
|
||||
})
|
||||
|
||||
Convey("Unmarshal IntArray", t, func() {
|
||||
bs, err := json.Marshal(v)
|
||||
So(err, ShouldBeNil)
|
||||
So(bs, ShouldResemble, []byte("[9,12,1024]"))
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user