// SPDX-FileCopyrightText: 2020 The Go Language Server Authors // SPDX-License-Identifier: BSD-3-Clause package protocol import ( "testing" "encoding/json" "github.com/google/go-cmp/cmp" "github.com/a-h/templ/lsp/uri" ) func TestDidOpenTextDocumentParams(t *testing.T) { t.Parallel() const ( want = `{"textDocument":{"uri":"file:///path/to/basic.go","languageId":"go","version":10,"text":"Go Language"}}` wantInvalid = `{"textDocument":{"uri":"file:///path/to/basic_gen.go","languageId":"cpp","version":10,"text":"C++ Language"}}` ) wantType := DidOpenTextDocumentParams{ TextDocument: TextDocumentItem{ URI: uri.File("/path/to/basic.go"), LanguageID: GoLanguage, Version: int32(10), Text: "Go Language", }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field DidOpenTextDocumentParams want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want DidOpenTextDocumentParams wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got DidOpenTextDocumentParams if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestDidChangeTextDocumentParams(t *testing.T) { t.Parallel() const ( want = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}]}` wantInvalid = `{"textDocument":{"uri":"file:///path/to/test.go","version":10},"contentChanges":[{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}]}` ) wantType := DidChangeTextDocumentParams{ TextDocument: VersionedTextDocumentIdentifier{ TextDocumentIdentifier: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, Version: int32(10), }, ContentChanges: []TextDocumentContentChangeEvent{ { Range: &Range{ Start: Position{ Line: 25, Character: 1, }, End: Position{ Line: 25, Character: 3, }, }, RangeLength: 2, Text: "testText", }, }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field DidChangeTextDocumentParams want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want DidChangeTextDocumentParams wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got DidChangeTextDocumentParams if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestTextDocumentSaveReason_String(t *testing.T) { t.Parallel() tests := []struct { name string k TextDocumentSaveReason want string }{ { name: "Manual", k: TextDocumentSaveReasonManual, want: "Manual", }, { name: "AfterDelay", k: TextDocumentSaveReasonAfterDelay, want: "AfterDelay", }, { name: "FocusOut", k: TextDocumentSaveReasonFocusOut, want: "FocusOut", }, { name: "Unknown", k: TextDocumentSaveReason(0), want: "0", }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() if got := tt.k.String(); got != tt.want { t.Errorf("TextDocumentSaveReason.String() = %v, want %v", tt.want, got) } }) } } func TestTextDocumentContentChangeEvent(t *testing.T) { t.Parallel() const ( want = `{"range":{"start":{"line":25,"character":1},"end":{"line":25,"character":3}},"rangeLength":2,"text":"testText"}` wantInvalid = `{"range":{"start":{"line":2,"character":1},"end":{"line":3,"character":4}},"rangeLength":3,"text":"invalidText"}` wantReplaceAll = `{"text":"replace all"}` ) wantType := TextDocumentContentChangeEvent{ Range: &Range{ Start: Position{ Line: 25, Character: 1, }, End: Position{ Line: 25, Character: 3, }, }, RangeLength: 2, Text: "testText", } wantReplaceAllType := TextDocumentContentChangeEvent{ Text: "replace all", } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field TextDocumentContentChangeEvent want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, { name: "ReplaceAll", field: wantReplaceAllType, want: wantReplaceAll, wantMarshalErr: false, wantErr: false, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want TextDocumentContentChangeEvent wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got TextDocumentContentChangeEvent if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestTextDocumentChangeRegistrationOptions(t *testing.T) { t.Parallel() const ( want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"syncKind":2}` wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"syncKind":1}` ) wantType := TextDocumentChangeRegistrationOptions{ TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ DocumentSelector: DocumentSelector{ { Language: "go", Scheme: "file", Pattern: "*.go", }, }, }, SyncKind: 2, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field TextDocumentChangeRegistrationOptions want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want TextDocumentChangeRegistrationOptions wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got TextDocumentChangeRegistrationOptions if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestWillSaveTextDocumentParams(t *testing.T) { t.Parallel() const ( want = `{"textDocument":{"uri":"file:///path/to/test.go"},"reason":3}` wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}` wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"},"reason":1}` ) wantType := WillSaveTextDocumentParams{ TextDocument: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, Reason: TextDocumentSaveReasonFocusOut, } wantTypeNilAll := WillSaveTextDocumentParams{ TextDocument: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field WillSaveTextDocumentParams want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantTypeNilAll, want: wantNilAll, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want WillSaveTextDocumentParams wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantNilAll, want: wantTypeNilAll, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got WillSaveTextDocumentParams if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestDidSaveTextDocumentParams(t *testing.T) { t.Parallel() const ( want = `{"text":"testText","textDocument":{"uri":"file:///path/to/test.go"}}` wantNilAll = `{"textDocument":{"uri":"file:///path/to/test.go"}}` wantInvalid = `{"text":"invalidText","textDocument":{"uri":"file:///path/to/invalid.go"}}` ) wantType := DidSaveTextDocumentParams{ Text: "testText", TextDocument: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, } wantTypeNilAll := DidSaveTextDocumentParams{ TextDocument: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field DidSaveTextDocumentParams want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantTypeNilAll, want: wantNilAll, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want DidSaveTextDocumentParams wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantNilAll, want: wantTypeNilAll, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got DidSaveTextDocumentParams if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestTextDocumentSaveRegistrationOptions(t *testing.T) { t.Parallel() const ( want = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}],"includeText":true}` wantNilAll = `{"documentSelector":[{"language":"go","scheme":"file","pattern":"*.go"}]}` wantInvalid = `{"documentSelector":[{"language":"typescript","scheme":"file","pattern":"*.{ts,js}"}],"includeText":false}` ) wantType := TextDocumentSaveRegistrationOptions{ TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ DocumentSelector: DocumentSelector{ { Language: "go", Scheme: "file", Pattern: "*.go", }, }, }, IncludeText: true, } wantTypeNilAll := TextDocumentSaveRegistrationOptions{ TextDocumentRegistrationOptions: TextDocumentRegistrationOptions{ DocumentSelector: DocumentSelector{ { Language: "go", Scheme: "file", Pattern: "*.go", }, }, }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field TextDocumentSaveRegistrationOptions want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantTypeNilAll, want: wantNilAll, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want TextDocumentSaveRegistrationOptions wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "ValidNilAll", field: wantNilAll, want: wantTypeNilAll, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got TextDocumentSaveRegistrationOptions if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) } func TestDidCloseTextDocumentParams(t *testing.T) { t.Parallel() const ( want = `{"textDocument":{"uri":"file:///path/to/test.go"}}` wantInvalid = `{"textDocument":{"uri":"file:///path/to/invalid.go"}}` ) wantType := DidCloseTextDocumentParams{ TextDocument: TextDocumentIdentifier{ URI: uri.File("/path/to/test.go"), }, } t.Run("Marshal", func(t *testing.T) { tests := []struct { name string field DidCloseTextDocumentParams want string wantMarshalErr bool wantErr bool }{ { name: "Valid", field: wantType, want: want, wantMarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantType, want: wantInvalid, wantMarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() got, err := json.Marshal(&tt.field) if (err != nil) != tt.wantMarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, string(got)); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) t.Run("Unmarshal", func(t *testing.T) { tests := []struct { name string field string want DidCloseTextDocumentParams wantUnmarshalErr bool wantErr bool }{ { name: "Valid", field: want, want: wantType, wantUnmarshalErr: false, wantErr: false, }, { name: "Invalid", field: wantInvalid, want: wantType, wantUnmarshalErr: false, wantErr: true, }, } for _, tt := range tests { tt := tt t.Run(tt.name, func(t *testing.T) { t.Parallel() var got DidCloseTextDocumentParams if err := json.Unmarshal([]byte(tt.field), &got); (err != nil) != tt.wantUnmarshalErr { t.Fatal(err) } if diff := cmp.Diff(tt.want, got); (diff != "") != tt.wantErr { t.Errorf("%s: wantErr: %t\n(-want +got)\n%s", tt.name, tt.wantErr, diff) } }) } }) }