mirror of
https://github.com/golang/go.git
synced 2024-09-21 18:38:37 +00:00
net/rpc: Create empty maps and slices as return type
When a map or slice is used as a return type create an empty value rather than a nil value. Fixes #19588 Change-Id: I577fd74956172329745d614ac37d4db8f737efb8 Reviewed-on: https://go-review.googlesource.com/38474 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
This commit is contained in:
parent
70ea0ec30f
commit
0ca8701ea2
@ -13,6 +13,7 @@ import (
|
||||
"io/ioutil"
|
||||
"net"
|
||||
"net/rpc"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -55,8 +56,26 @@ func (t *Arith) Error(args *Args, reply *Reply) error {
|
||||
panic("ERROR")
|
||||
}
|
||||
|
||||
type BuiltinTypes struct{}
|
||||
|
||||
func (BuiltinTypes) Map(i int, reply *map[int]int) error {
|
||||
(*reply)[i] = i
|
||||
return nil
|
||||
}
|
||||
|
||||
func (BuiltinTypes) Slice(i int, reply *[]int) error {
|
||||
*reply = append(*reply, i)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (BuiltinTypes) Array(i int, reply *[1]int) error {
|
||||
(*reply)[0] = i
|
||||
return nil
|
||||
}
|
||||
|
||||
func init() {
|
||||
rpc.Register(new(Arith))
|
||||
rpc.Register(BuiltinTypes{})
|
||||
}
|
||||
|
||||
func TestServerNoParams(t *testing.T) {
|
||||
@ -182,6 +201,45 @@ func TestClient(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinTypes(t *testing.T) {
|
||||
cli, srv := net.Pipe()
|
||||
go ServeConn(srv)
|
||||
|
||||
client := NewClient(cli)
|
||||
defer client.Close()
|
||||
|
||||
// Map
|
||||
arg := 7
|
||||
replyMap := map[int]int{}
|
||||
err := client.Call("BuiltinTypes.Map", arg, &replyMap)
|
||||
if err != nil {
|
||||
t.Errorf("Map: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if replyMap[arg] != arg {
|
||||
t.Errorf("Map: expected %d got %d", arg, replyMap[arg])
|
||||
}
|
||||
|
||||
// Slice
|
||||
replySlice := []int{}
|
||||
err = client.Call("BuiltinTypes.Slice", arg, &replySlice)
|
||||
if err != nil {
|
||||
t.Errorf("Slice: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if e := []int{arg}; !reflect.DeepEqual(replySlice, e) {
|
||||
t.Errorf("Slice: expected %v got %v", e, replySlice)
|
||||
}
|
||||
|
||||
// Array
|
||||
replyArray := [1]int{}
|
||||
err = client.Call("BuiltinTypes.Array", arg, &replyArray)
|
||||
if err != nil {
|
||||
t.Errorf("Array: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if e := [1]int{arg}; !reflect.DeepEqual(replyArray, e) {
|
||||
t.Errorf("Array: expected %v got %v", e, replyArray)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMalformedInput(t *testing.T) {
|
||||
cli, srv := net.Pipe()
|
||||
go cli.Write([]byte(`{id:1}`)) // invalid json
|
||||
|
@ -571,6 +571,13 @@ func (server *Server) readRequest(codec ServerCodec) (service *service, mtype *m
|
||||
}
|
||||
|
||||
replyv = reflect.New(mtype.ReplyType.Elem())
|
||||
|
||||
switch mtype.ReplyType.Elem().Kind() {
|
||||
case reflect.Map:
|
||||
replyv.Elem().Set(reflect.MakeMap(mtype.ReplyType.Elem()))
|
||||
case reflect.Slice:
|
||||
replyv.Elem().Set(reflect.MakeSlice(mtype.ReplyType.Elem(), 0, 0))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ import (
|
||||
"log"
|
||||
"net"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
@ -85,6 +86,24 @@ type Embed struct {
|
||||
hidden
|
||||
}
|
||||
|
||||
type BuiltinTypes struct{}
|
||||
|
||||
func (BuiltinTypes) Map(args *Args, reply *map[int]int) error {
|
||||
(*reply)[args.A] = args.B
|
||||
return nil
|
||||
}
|
||||
|
||||
func (BuiltinTypes) Slice(args *Args, reply *[]int) error {
|
||||
*reply = append(*reply, args.A, args.B)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (BuiltinTypes) Array(args *Args, reply *[2]int) error {
|
||||
(*reply)[0] = args.A
|
||||
(*reply)[1] = args.B
|
||||
return nil
|
||||
}
|
||||
|
||||
func listenTCP() (net.Listener, string) {
|
||||
l, e := net.Listen("tcp", "127.0.0.1:0") // any available address
|
||||
if e != nil {
|
||||
@ -97,6 +116,7 @@ func startServer() {
|
||||
Register(new(Arith))
|
||||
Register(new(Embed))
|
||||
RegisterName("net.rpc.Arith", new(Arith))
|
||||
Register(BuiltinTypes{})
|
||||
|
||||
var l net.Listener
|
||||
l, serverAddr = listenTCP()
|
||||
@ -326,6 +346,49 @@ func testHTTPRPC(t *testing.T, path string) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuiltinTypes(t *testing.T) {
|
||||
once.Do(startServer)
|
||||
|
||||
client, err := DialHTTP("tcp", httpServerAddr)
|
||||
if err != nil {
|
||||
t.Fatal("dialing", err)
|
||||
}
|
||||
defer client.Close()
|
||||
|
||||
// Map
|
||||
args := &Args{7, 8}
|
||||
replyMap := map[int]int{}
|
||||
err = client.Call("BuiltinTypes.Map", args, &replyMap)
|
||||
if err != nil {
|
||||
t.Errorf("Map: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if replyMap[args.A] != args.B {
|
||||
t.Errorf("Map: expected %d got %d", args.B, replyMap[args.A])
|
||||
}
|
||||
|
||||
// Slice
|
||||
args = &Args{7, 8}
|
||||
replySlice := []int{}
|
||||
err = client.Call("BuiltinTypes.Slice", args, &replySlice)
|
||||
if err != nil {
|
||||
t.Errorf("Slice: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if e := []int{args.A, args.B}; !reflect.DeepEqual(replySlice, e) {
|
||||
t.Errorf("Slice: expected %v got %v", e, replySlice)
|
||||
}
|
||||
|
||||
// Array
|
||||
args = &Args{7, 8}
|
||||
replyArray := [2]int{}
|
||||
err = client.Call("BuiltinTypes.Array", args, &replyArray)
|
||||
if err != nil {
|
||||
t.Errorf("Array: expected no error but got string %q", err.Error())
|
||||
}
|
||||
if e := [2]int{args.A, args.B}; !reflect.DeepEqual(replyArray, e) {
|
||||
t.Errorf("Array: expected %v got %v", e, replyArray)
|
||||
}
|
||||
}
|
||||
|
||||
// CodecEmulator provides a client-like api and a ServerCodec interface.
|
||||
// Can be used to test ServeRequest.
|
||||
type CodecEmulator struct {
|
||||
|
Loading…
Reference in New Issue
Block a user