| // Copyright 2020 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package jsonrpc2_test |
| |
| import ( |
| "bytes" |
| "encoding/json" |
| "reflect" |
| "testing" |
| |
| "golang.org/x/exp/jsonrpc2" |
| ) |
| |
| func TestWireMessage(t *testing.T) { |
| for _, test := range []struct { |
| name string |
| msg jsonrpc2.Message |
| encoded []byte |
| }{{ |
| name: "notification", |
| msg: newNotification("alive", nil), |
| encoded: []byte(`{"jsonrpc":"2.0","method":"alive"}`), |
| }, { |
| name: "call", |
| msg: newCall("msg1", "ping", nil), |
| encoded: []byte(`{"jsonrpc":"2.0","id":"msg1","method":"ping"}`), |
| }, { |
| name: "response", |
| msg: newResponse("msg2", "pong", nil), |
| encoded: []byte(`{"jsonrpc":"2.0","id":"msg2","result":"pong"}`), |
| }, { |
| name: "numerical id", |
| msg: newCall(1, "poke", nil), |
| encoded: []byte(`{"jsonrpc":"2.0","id":1,"method":"poke"}`), |
| }, { |
| // originally reported in #39719, this checks that result is not present if |
| // it is an error response |
| name: "computing fix edits", |
| msg: newResponse(3, nil, jsonrpc2.NewError(0, "computing fix edits")), |
| encoded: []byte(`{ |
| "jsonrpc":"2.0", |
| "id":3, |
| "error":{ |
| "code":0, |
| "message":"computing fix edits" |
| } |
| }`), |
| }} { |
| b, err := jsonrpc2.EncodeMessage(test.msg) |
| if err != nil { |
| t.Fatal(err) |
| } |
| checkJSON(t, b, test.encoded) |
| msg, err := jsonrpc2.DecodeMessage(test.encoded) |
| if err != nil { |
| t.Fatal(err) |
| } |
| if !reflect.DeepEqual(msg, test.msg) { |
| t.Errorf("decoded message does not match\nGot:\n%+#v\nWant:\n%+#v", msg, test.msg) |
| } |
| } |
| } |
| |
| func newNotification(method string, params interface{}) jsonrpc2.Message { |
| msg, err := jsonrpc2.NewNotification(method, params) |
| if err != nil { |
| panic(err) |
| } |
| return msg |
| } |
| |
| func newID(id interface{}) jsonrpc2.ID { |
| switch v := id.(type) { |
| case nil: |
| return jsonrpc2.ID{} |
| case string: |
| return jsonrpc2.StringID(v) |
| case int: |
| return jsonrpc2.Int64ID(int64(v)) |
| case int64: |
| return jsonrpc2.Int64ID(v) |
| default: |
| panic("invalid ID type") |
| } |
| } |
| |
| func newCall(id interface{}, method string, params interface{}) jsonrpc2.Message { |
| msg, err := jsonrpc2.NewCall(newID(id), method, params) |
| if err != nil { |
| panic(err) |
| } |
| return msg |
| } |
| |
| func newResponse(id interface{}, result interface{}, rerr error) jsonrpc2.Message { |
| msg, err := jsonrpc2.NewResponse(newID(id), result, rerr) |
| if err != nil { |
| panic(err) |
| } |
| return msg |
| } |
| |
| func checkJSON(t *testing.T, got, want []byte) { |
| // compare the compact form, to allow for formatting differences |
| g := &bytes.Buffer{} |
| if err := json.Compact(g, []byte(got)); err != nil { |
| t.Fatal(err) |
| } |
| w := &bytes.Buffer{} |
| if err := json.Compact(w, []byte(want)); err != nil { |
| t.Fatal(err) |
| } |
| if g.String() != w.String() { |
| t.Errorf("encoded message does not match\nGot:\n%s\nWant:\n%s", g, w) |
| } |
| } |