| // 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" | |
| jsonrpc2 "golang.org/x/tools/internal/jsonrpc2_v2" | |
| ) | |
| 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 any) jsonrpc2.Message { | |
| msg, err := jsonrpc2.NewNotification(method, params) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return msg | |
| } | |
| func newID(id any) 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 any, method string, params any) jsonrpc2.Message { | |
| msg, err := jsonrpc2.NewCall(newID(id), method, params) | |
| if err != nil { | |
| panic(err) | |
| } | |
| return msg | |
| } | |
| func newResponse(id any, result any, 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) | |
| } | |
| } |