--- /dev/null
+// 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"
+ "fmt"
+ "testing"
+
+ "golang.org/x/tools/internal/jsonrpc2"
+)
+
+var wireIDTestData = []struct {
+ name string
+ id jsonrpc2.ID
+ encoded []byte
+ plain string
+ quoted string
+}{
+ {
+ name: `empty`,
+ encoded: []byte(`0`),
+ plain: `0`,
+ quoted: `#0`,
+ }, {
+ name: `number`,
+ id: jsonrpc2.NewIntID(43),
+ encoded: []byte(`43`),
+ plain: `43`,
+ quoted: `#43`,
+ }, {
+ name: `string`,
+ id: jsonrpc2.NewStringID("life"),
+ encoded: []byte(`"life"`),
+ plain: `life`,
+ quoted: `"life"`,
+ },
+}
+
+func TestIDFormat(t *testing.T) {
+ for _, test := range wireIDTestData {
+ t.Run(test.name, func(t *testing.T) {
+ if got := fmt.Sprint(test.id); got != test.plain {
+ t.Errorf("got %s expected %s", got, test.plain)
+ }
+ if got := fmt.Sprintf("%q", test.id); got != test.quoted {
+ t.Errorf("got %s want %s", got, test.quoted)
+ }
+ })
+ }
+}
+
+func TestIDEncode(t *testing.T) {
+ for _, test := range wireIDTestData {
+ t.Run(test.name, func(t *testing.T) {
+ data, err := json.Marshal(&test.id)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkJSON(t, data, test.encoded)
+ })
+ }
+}
+
+func TestIDDecode(t *testing.T) {
+ for _, test := range wireIDTestData {
+ t.Run(test.name, func(t *testing.T) {
+ var got *jsonrpc2.ID
+ if err := json.Unmarshal(test.encoded, &got); err != nil {
+ t.Fatal(err)
+ }
+ if got == nil {
+ t.Errorf("got nil want %s", test.id)
+ } else if *got != test.id {
+ t.Errorf("got %s want %s", got, test.id)
+ }
+ })
+ }
+}
+
+func TestErrorEncode(t *testing.T) {
+ b, err := json.Marshal(jsonrpc2.NewError(0, ""))
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkJSON(t, b, []byte(`{
+ "code": 0,
+ "message": ""
+ }`))
+}
+
+func TestErrorResponse(t *testing.T) {
+ // originally reported in #39719, this checks that result is not present if
+ // it is an error response
+ r, _ := jsonrpc2.NewResponse(jsonrpc2.NewIntID(3), nil, fmt.Errorf("computing fix edits"))
+ data, err := json.Marshal(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkJSON(t, data, []byte(`{
+ "jsonrpc":"2.0",
+ "error":{
+ "code":0,
+ "message":"computing fix edits"
+ },
+ "id":3
+ }`))
+}
+
+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.Fatalf("Got:\n%s\nWant:\n%s", g, w)
+ }
+}