diff --git a/encoding/form/form_test.go b/encoding/form/form_test.go index 647d1edc8..013edbd1d 100644 --- a/encoding/form/form_test.go +++ b/encoding/form/form_test.go @@ -21,11 +21,6 @@ type LoginRequest struct { Password string `json:"password,omitempty"` } -type TestModel struct { - ID int32 `json:"id"` - Name string `json:"name"` -} - func TestFormCodecMarshal(t *testing.T) { req := &LoginRequest{ Username: "kratos", @@ -33,10 +28,10 @@ func TestFormCodecMarshal(t *testing.T) { } content, err := encoding.GetCodec(Name).Marshal(req) if err != nil { - t.Errorf("marshal error: %v", err) + t.Fatal(err) } if !reflect.DeepEqual([]byte("password=kratos_pwd&username=kratos"), content) { - t.Errorf("expect %v, got %v", []byte("password=kratos_pwd&username=kratos"), content) + t.Errorf("expect %s, got %s", "password=kratos_pwd&username=kratos", content) } req = &LoginRequest{ @@ -45,23 +40,25 @@ func TestFormCodecMarshal(t *testing.T) { } content, err = encoding.GetCodec(Name).Marshal(req) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } if !reflect.DeepEqual([]byte("username=kratos"), content) { - t.Errorf("expect %v, got %v", []byte("username=kratos"), content) + t.Errorf("expect %s, got %s", "username=kratos", content) } - m := &TestModel{ + m := struct { + ID int32 `json:"id"` + Name string `json:"name"` + }{ ID: 1, Name: "kratos", } content, err = encoding.GetCodec(Name).Marshal(m) - t.Log(string(content)) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } if !reflect.DeepEqual([]byte("id=1&name=kratos"), content) { - t.Errorf("expect %v, got %v", []byte("id=1&name=kratos"), content) + t.Errorf("expect %s, got %s", "id=1&name=kratos", content) } } @@ -72,13 +69,13 @@ func TestFormCodecUnmarshal(t *testing.T) { } content, err := encoding.GetCodec(Name).Marshal(req) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } bindReq := new(LoginRequest) err = encoding.GetCodec(Name).Unmarshal(content, bindReq) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } if !reflect.DeepEqual("kratos", bindReq.Username) { t.Errorf("expect %v, got %v", "kratos", bindReq.Username) @@ -119,41 +116,41 @@ func TestProtoEncodeDecode(t *testing.T) { } content, err := encoding.GetCodec(Name).Marshal(in) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } - if !reflect.DeepEqual("a=19&age=18&b=true&bool=false&byte=MTIz&bytes=MTIz&count=3&d=22.22&double=12.33&duration="+ + if "a=19&age=18&b=true&bool=false&byte=MTIz&bytes=MTIz&count=3&d=22.22&double=12.33&duration="+ "2m0.000000022s&field=1%2C2&float=12.34&id=2233&int32=32&int64=64&map%5Bkratos%5D=https%3A%2F%2Fgo-kratos.dev%2F&"+ "numberOne=2233&price=11.23&sex=woman&simples=3344&simples=5566&string=go-kratos"+ - "×tamp=1970-01-01T00%3A00%3A20.000000002Z&uint32=32&uint64=64&very_simple.component=5566", string(content)) { - t.Errorf("rawpath is not equal to %v", string(content)) + "×tamp=1970-01-01T00%3A00%3A20.000000002Z&uint32=32&uint64=64&very_simple.component=5566" != string(content) { + t.Errorf("rawpath is not equal to %s", content) } in2 := &complex.Complex{} err = encoding.GetCodec(Name).Unmarshal(content, in2) if err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } - if !reflect.DeepEqual(int64(2233), in2.Id) { + if int64(2233) != in2.Id { t.Errorf("expect %v, got %v", int64(2233), in2.Id) } - if !reflect.DeepEqual("2233", in2.NoOne) { + if "2233" != in2.NoOne { t.Errorf("expect %v, got %v", "2233", in2.NoOne) } - if reflect.DeepEqual(in2.Simple, nil) { + if in2.Simple == nil { t.Errorf("expect %v, got %v", nil, in2.Simple) } - if !reflect.DeepEqual("5566", in2.Simple.Component) { + if "5566" != in2.Simple.Component { t.Errorf("expect %v, got %v", "5566", in2.Simple.Component) } - if reflect.DeepEqual(in2.Simples, nil) { + if in2.Simples == nil { t.Errorf("expect %v, got %v", nil, in2.Simples) } - if !reflect.DeepEqual(len(in2.Simples), 2) { + if len(in2.Simples) != 2 { t.Errorf("expect %v, got %v", 2, len(in2.Simples)) } - if !reflect.DeepEqual("3344", in2.Simples[0]) { + if "3344" != in2.Simples[0] { t.Errorf("expect %v, got %v", "3344", in2.Simples[0]) } - if !reflect.DeepEqual("5566", in2.Simples[1]) { + if "5566" != in2.Simples[1] { t.Errorf("expect %v, got %v", "5566", in2.Simples[1]) } } @@ -162,19 +159,18 @@ func TestDecodeStructPb(t *testing.T) { req := new(ectest.StructPb) query := `data={"name":"kratos"}&data_list={"name1": "kratos"}&data_list={"name2": "go-kratos"}` if err := encoding.GetCodec(Name).Unmarshal([]byte(query), req); err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Fatal(err) } - if !reflect.DeepEqual("kratos", req.Data.GetFields()["name"].GetStringValue()) { + if "kratos" != req.Data.GetFields()["name"].GetStringValue() { t.Errorf("except %v, got %v", "kratos", req.Data.GetFields()["name"].GetStringValue()) } if len(req.DataList) != 2 { - t.Errorf("execpt %v, got %v", 2, len(req.DataList)) - return + t.Fatalf("execpt %v, got %v", 2, len(req.DataList)) } - if !reflect.DeepEqual("kratos", req.DataList[0].GetFields()["name1"].GetStringValue()) { + if "kratos" != req.DataList[0].GetFields()["name1"].GetStringValue() { t.Errorf("except %v, got %v", "kratos", req.Data.GetFields()["name1"].GetStringValue()) } - if !reflect.DeepEqual("go-kratos", req.DataList[1].GetFields()["name2"].GetStringValue()) { + if "go-kratos" != req.DataList[1].GetFields()["name2"].GetStringValue() { t.Errorf("except %v, got %v", "go-kratos", req.Data.GetFields()["name2"].GetStringValue()) } } @@ -185,10 +181,10 @@ func TestDecodeBytesValuePb(t *testing.T) { content := "bytes=" + val in2 := &complex.Complex{} if err := encoding.GetCodec(Name).Unmarshal([]byte(content), in2); err != nil { - t.Errorf("expect %v, got %v", nil, err) + t.Error(err) } - if !reflect.DeepEqual(url, string(in2.Bytes.Value)) { - t.Errorf("except %v, got %v", val, string(in2.Bytes.Value)) + if url != string(in2.Bytes.Value) { + t.Errorf("except %s, got %s", val, in2.Bytes.Value) } } @@ -198,8 +194,6 @@ func TestEncodeFieldMask(t *testing.T) { } if v := EncodeFieldMask(req.ProtoReflect()); v != "updateMask=foo,bar" { t.Errorf("got %s", v) - } else { - t.Log(v) } } @@ -210,9 +204,8 @@ func TestOptional(t *testing.T) { Sub: &bdtest.Sub{Name: "bar"}, OptInt32: &v, } - if v, _ := EncodeValues(req); v.Encode() != "name=foo&optInt32=100&sub.naming=bar" { - t.Errorf("got %s", v.Encode()) - } else { - t.Log(v) + query, _ := EncodeValues(req) + if query.Encode() != "name=foo&optInt32=100&sub.naming=bar" { + t.Fatalf("got %s", query.Encode()) } } diff --git a/encoding/form/proto_encode.go b/encoding/form/proto_encode.go index 94eac6ab8..25d4ac192 100644 --- a/encoding/form/proto_encode.go +++ b/encoding/form/proto_encode.go @@ -46,10 +46,8 @@ func encodeByField(u url.Values, path string, m protoreflect.Message) (finalErr newPath = path + "." + key } if of := fd.ContainingOneof(); of != nil { - if f := m.WhichOneof(of); f != nil { - if f != fd { - return true - } + if f := m.WhichOneof(of); f != nil && f != fd { + return true } } switch { @@ -60,7 +58,9 @@ func encodeByField(u url.Values, path string, m protoreflect.Message) (finalErr finalErr = err return false } - u[newPath] = list + for _, item := range list { + u.Add(newPath, item) + } } case fd.IsMap(): if v.Map().Len() > 0 { @@ -70,13 +70,13 @@ func encodeByField(u url.Values, path string, m protoreflect.Message) (finalErr return false } for k, value := range m { - u[fmt.Sprintf("%s[%s]", newPath, k)] = []string{value} + u.Set(fmt.Sprintf("%s[%s]", newPath, k), value) } } case (fd.Kind() == protoreflect.MessageKind) || (fd.Kind() == protoreflect.GroupKind): value, err := encodeMessage(fd.Message(), v) if err == nil { - u[newPath] = []string{value} + u.Set(newPath, value) return true } if err = encodeByField(u, newPath, v.Message()); err != nil { @@ -89,7 +89,7 @@ func encodeByField(u url.Values, path string, m protoreflect.Message) (finalErr finalErr = err return false } - u[newPath] = []string{value} + u.Set(newPath, value) } return true }) diff --git a/encoding/form/proto_encode_test.go b/encoding/form/proto_encode_test.go new file mode 100644 index 000000000..7d0cfa9ea --- /dev/null +++ b/encoding/form/proto_encode_test.go @@ -0,0 +1,110 @@ +package form + +import ( + "testing" + + "google.golang.org/protobuf/types/known/durationpb" + "google.golang.org/protobuf/types/known/fieldmaskpb" + "google.golang.org/protobuf/types/known/timestamppb" + "google.golang.org/protobuf/types/known/wrapperspb" + + "github.com/go-kratos/kratos/v2/internal/testdata/complex" +) + +func TestEncodeValues(t *testing.T) { + in := &complex.Complex{ + Id: 2233, + NoOne: "2233", + Simple: &complex.Simple{Component: "5566"}, + Simples: []string{"3344", "5566"}, + B: true, + Sex: complex.Sex_woman, + Age: 18, + A: 19, + Count: 3, + Price: 11.23, + D: 22.22, + Byte: []byte("123"), + Map: map[string]string{"kratos": "https://go-kratos.dev/", "kratos_start": "https://go-kratos.dev/en/docs/getting-started/start/"}, + + Timestamp: ×tamppb.Timestamp{Seconds: 20, Nanos: 2}, + Duration: &durationpb.Duration{Seconds: 120, Nanos: 22}, + Field: &fieldmaskpb.FieldMask{Paths: []string{"1", "2"}}, + Double: &wrapperspb.DoubleValue{Value: 12.33}, + Float: &wrapperspb.FloatValue{Value: 12.34}, + Int64: &wrapperspb.Int64Value{Value: 64}, + Int32: &wrapperspb.Int32Value{Value: 32}, + Uint64: &wrapperspb.UInt64Value{Value: 64}, + Uint32: &wrapperspb.UInt32Value{Value: 32}, + Bool: &wrapperspb.BoolValue{Value: false}, + String_: &wrapperspb.StringValue{Value: "go-kratos"}, + Bytes: &wrapperspb.BytesValue{Value: []byte("123")}, + } + query, err := EncodeValues(in) + if err != nil { + t.Fatal(err) + } + want := "a=19&age=18&b=true&bool=false&byte=MTIz&bytes=MTIz&count=3&d=22.22&double=12.33&duration=2m0.000000022s&field=1%2C2&float=12.34&id=2233&int32=32&int64=64&map%5Bkratos%5D=https%3A%2F%2Fgo-kratos.dev%2F&map%5Bkratos_start%5D=https%3A%2F%2Fgo-kratos.dev%2Fen%2Fdocs%2Fgetting-started%2Fstart%2F&numberOne=2233&price=11.23&sex=woman&simples=3344&simples=5566&string=go-kratos×tamp=1970-01-01T00%3A00%3A20.000000002Z&uint32=32&uint64=64&very_simple.component=5566" // nolint:lll + if got := query.Encode(); want != got { + t.Errorf("want: %s, got: %s", want, got) + } +} + +func TestJsonCamelCase(t *testing.T) { + tests := []struct { + camelCase string + snakeCase string + }{ + { + "userId", "user_id", + }, + { + "user", "user", + }, + { + "userIdAndUsername", "user_id_and_username", + }, + { + "", "", + }, + } + for _, test := range tests { + t.Run(test.snakeCase, func(t *testing.T) { + camel := jsonCamelCase(test.snakeCase) + if camel != test.camelCase { + t.Errorf("want: %s, got: %s", test.camelCase, camel) + } + }) + } +} + +func TestIsASCIILower(t *testing.T) { + tests := []struct { + b byte + lower bool + }{ + { + 'A', false, + }, + { + 'a', true, + }, + { + ',', false, + }, + { + '1', false, + }, + { + ' ', false, + }, + } + for _, test := range tests { + t.Run(string(test.b), func(t *testing.T) { + lower := isASCIILower(test.b) + if test.lower != lower { + t.Errorf("'%s' is not ascii lower", string(test.b)) + } + }) + } +} diff --git a/encoding/form/well_known_types_test.go b/encoding/form/well_known_types_test.go index 5598211b0..5018cf7a0 100644 --- a/encoding/form/well_known_types_test.go +++ b/encoding/form/well_known_types_test.go @@ -26,12 +26,12 @@ func TestMarshalTimeStamp(t *testing.T) { }, } for _, v := range tests { - content, err := marshalTimestamp(v.input.ProtoReflect()) + got, err := marshalTimestamp(v.input.ProtoReflect()) if err != nil { - t.Errorf("expect %v,got %v", nil, err) + t.Fatal(err) } - if got, want := content, v.expect; got != want { - t.Errorf("expect %v,got %v", want, got) + if want := v.expect; got != want { + t.Errorf("expect %v, got %v", want, got) } } } @@ -59,12 +59,12 @@ func TestMarshalDuration(t *testing.T) { }, } for _, v := range tests { - content, err := marshalDuration(v.input.ProtoReflect()) + got, err := marshalDuration(v.input.ProtoReflect()) if err != nil { - t.Errorf("expect %v,got %v", nil, err) + t.Fatal(err) } - if got, want := content, v.expect; got != want { - t.Errorf("expect %v,got %v", want, got) + if want := v.expect; got != want { + t.Errorf("expect %s, got %s", want, got) } } } @@ -84,12 +84,12 @@ func TestMarshalBytes(t *testing.T) { }, } for _, v := range tests { - content, err := marshalBytes(v.input) + got, err := marshalBytes(v.input) if err != nil { - t.Errorf("expect %v,got %v", nil, err) + t.Fatal(err) } - if got, want := content, v.expect; got != want { - t.Errorf("expect %v,got %v", want, got) + if want := v.expect; got != want { + t.Errorf("expect %v, got %v", want, got) } } } diff --git a/encoding/proto/proto.go b/encoding/proto/proto.go index 96051a969..0da5e0dcb 100644 --- a/encoding/proto/proto.go +++ b/encoding/proto/proto.go @@ -3,9 +3,9 @@ package proto import ( - "github.com/go-kratos/kratos/v2/encoding" - "google.golang.org/protobuf/proto" + + "github.com/go-kratos/kratos/v2/encoding" ) // Name is the name registered for the proto compressor.