mirror of
https://github.com/laravel-ls/protocol.git
synced 2026-06-16 03:54:56 +02:00
321 lines
11 KiB
Go
321 lines
11 KiB
Go
package protocol_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/laravel-ls/protocol"
|
|
)
|
|
|
|
func Test_CapabilitiesServer_UnmarshalValidJSON(t *testing.T) {
|
|
data := []byte(`{
|
|
"positionEncoding": "utf-16",
|
|
"textDocumentSync": 2,
|
|
"completionProvider": {
|
|
"triggerCharacters": [".", ":"],
|
|
"resolveProvider": true,
|
|
"completionItem": {
|
|
"labelDetailsSupport": true
|
|
}
|
|
},
|
|
"hoverProvider": true,
|
|
"definitionProvider": true,
|
|
"codeActionProvider": true,
|
|
"signatureHelpProvider": {
|
|
"triggerCharacters": ["(", ","],
|
|
"retriggerCharacters": [")"]
|
|
},
|
|
"diagnosticProvider": {
|
|
"interFileDependencies": true,
|
|
"workspaceDiagnostics": true
|
|
}
|
|
}`)
|
|
|
|
var decoded protocol.ServerCapabilities
|
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
|
t.Fatalf("unmarshal failed: %v", err)
|
|
}
|
|
|
|
positionEncoding := protocol.PositionEncodingKindUTF16
|
|
if decoded.PositionEncoding == nil || *decoded.PositionEncoding != positionEncoding {
|
|
t.Fatalf("expected positionEncoding=%q, got %+v", positionEncoding, decoded.PositionEncoding)
|
|
}
|
|
|
|
if decoded.CompletionProvider == nil {
|
|
t.Fatalf("expected completionProvider to be present")
|
|
}
|
|
|
|
if decoded.CompletionProvider.ResolveProvider == nil || !*decoded.CompletionProvider.ResolveProvider {
|
|
t.Fatalf("expected completionProvider.resolveProvider=true")
|
|
}
|
|
|
|
if decoded.CompletionProvider.CompletionItem == nil {
|
|
t.Fatalf("expected completionProvider.completionItem to be present")
|
|
}
|
|
|
|
if decoded.CompletionProvider.CompletionItem.LabelDetailsSupport == nil || !*decoded.CompletionProvider.CompletionItem.LabelDetailsSupport {
|
|
t.Fatalf("expected completionProvider.completionItem.labelDetailsSupport=true")
|
|
}
|
|
|
|
textDocumentSync, ok := decoded.TextDocumentSync.(float64)
|
|
if !ok || int(textDocumentSync) != int(protocol.TextDocumentSyncKindIncremental) {
|
|
t.Fatalf("expected textDocumentSync=%d, got %#v", protocol.TextDocumentSyncKindIncremental, decoded.TextDocumentSync)
|
|
}
|
|
|
|
diagnosticProvider, ok := decoded.DiagnosticProvider.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected diagnosticProvider object, got %#v", decoded.DiagnosticProvider)
|
|
}
|
|
|
|
if inter, ok := diagnosticProvider["interFileDependencies"].(bool); !ok || !inter {
|
|
t.Fatalf("expected diagnosticProvider.interFileDependencies=true, got %#v", diagnosticProvider["interFileDependencies"])
|
|
}
|
|
|
|
if ws, ok := diagnosticProvider["workspaceDiagnostics"].(bool); !ok || !ws {
|
|
t.Fatalf("expected diagnosticProvider.workspaceDiagnostics=true, got %#v", diagnosticProvider["workspaceDiagnostics"])
|
|
}
|
|
}
|
|
|
|
func Test_CapabilitiesServer_MarshalOmitEmptyFields(t *testing.T) {
|
|
original := protocol.ServerCapabilities{}
|
|
|
|
data, err := json.Marshal(original)
|
|
if err != nil {
|
|
t.Fatalf("marshal failed: %v", err)
|
|
}
|
|
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(data, &payload); err != nil {
|
|
t.Fatalf("unmarshal failed: %v", err)
|
|
}
|
|
|
|
if len(payload) != 0 {
|
|
t.Fatalf("expected empty JSON object from zero-value capabilities, got: %s", string(data))
|
|
}
|
|
}
|
|
|
|
func Test_CapabilitiesServer_UnmarshalExtendedFields(t *testing.T) {
|
|
data := []byte(`{
|
|
"textDocumentSync": {
|
|
"openClose": true,
|
|
"change": 2,
|
|
"save": {"includeText": true}
|
|
},
|
|
"notebookDocumentSync": {
|
|
"notebookSelector": [
|
|
{
|
|
"notebook": {"notebookType": "jupyter-notebook"},
|
|
"cells": [{"language": "python"}]
|
|
}
|
|
],
|
|
"save": true
|
|
},
|
|
"hoverProvider": {"workDoneProgress": true},
|
|
"declarationProvider": true,
|
|
"typeDefinitionProvider": {"workDoneProgress": true},
|
|
"implementationProvider": true,
|
|
"referencesProvider": {"workDoneProgress": true},
|
|
"documentHighlightProvider": true,
|
|
"documentSymbolProvider": {"workDoneProgress": true},
|
|
"codeActionProvider": {"codeActionKinds": ["quickfix"], "resolveProvider": true},
|
|
"codeLensProvider": {"resolveProvider": true},
|
|
"documentLinkProvider": {"resolveProvider": true},
|
|
"colorProvider": true,
|
|
"documentFormattingProvider": true,
|
|
"documentRangeFormattingProvider": true,
|
|
"documentOnTypeFormattingProvider": {"firstTriggerCharacter": ";", "moreTriggerCharacter": [","]},
|
|
"renameProvider": {"prepareProvider": true},
|
|
"foldingRangeProvider": true,
|
|
"executeCommandProvider": {"commands": ["laravel.run"], "workDoneProgress": true},
|
|
"selectionRangeProvider": {"workDoneProgress": true},
|
|
"linkedEditingRangeProvider": true,
|
|
"callHierarchyProvider": true,
|
|
"semanticTokensProvider": {
|
|
"legend": {"tokenTypes": ["class"], "tokenModifiers": ["declaration"]},
|
|
"full": true
|
|
},
|
|
"monikerProvider": true,
|
|
"typeHierarchyProvider": true,
|
|
"inlineValueProvider": true,
|
|
"inlayHintProvider": {"resolveProvider": true},
|
|
"workspaceSymbolProvider": {"resolveProvider": true},
|
|
"workspace": {
|
|
"workspaceFolders": {"supported": true, "changeNotifications": "workspaceFolders"},
|
|
"fileOperations": {
|
|
"didCreate": {
|
|
"filters": [
|
|
{"scheme": "file", "pattern": {"glob": "**/*.go"}}
|
|
]
|
|
}
|
|
}
|
|
}
|
|
}`)
|
|
|
|
var decoded protocol.ServerCapabilities
|
|
if err := json.Unmarshal(data, &decoded); err != nil {
|
|
t.Fatalf("unmarshal failed: %v", err)
|
|
}
|
|
|
|
if decoded.CodeLensProvider == nil || !decoded.CodeLensProvider.ResolveProvider {
|
|
t.Fatalf("expected codeLensProvider.resolveProvider=true")
|
|
}
|
|
|
|
if decoded.DocumentLinkProvider == nil || !decoded.DocumentLinkProvider.ResolveProvider {
|
|
t.Fatalf("expected documentLinkProvider.resolveProvider=true")
|
|
}
|
|
|
|
if decoded.DocumentOnTypeFormattingProvider == nil || decoded.DocumentOnTypeFormattingProvider.FirstTriggerCharacter != ";" {
|
|
t.Fatalf("expected documentOnTypeFormattingProvider.firstTriggerCharacter=';' got %#v", decoded.DocumentOnTypeFormattingProvider)
|
|
}
|
|
|
|
if decoded.ExecuteCommandProvider == nil || len(decoded.ExecuteCommandProvider.Commands) != 1 || decoded.ExecuteCommandProvider.Commands[0] != "laravel.run" {
|
|
t.Fatalf("expected executeCommandProvider.commands to contain laravel.run")
|
|
}
|
|
|
|
if decoded.Workspace == nil || decoded.Workspace.WorkspaceFolders == nil || !decoded.Workspace.WorkspaceFolders.Supported {
|
|
t.Fatalf("expected workspace.workspaceFolders.supported=true")
|
|
}
|
|
|
|
tds, ok := decoded.TextDocumentSync.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected textDocumentSync object, got %#v", decoded.TextDocumentSync)
|
|
}
|
|
|
|
if openClose, ok := tds["openClose"].(bool); !ok || !openClose {
|
|
t.Fatalf("expected textDocumentSync.openClose=true, got %#v", tds["openClose"])
|
|
}
|
|
|
|
hover, ok := decoded.HoverProvider.(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected hoverProvider object, got %#v", decoded.HoverProvider)
|
|
}
|
|
|
|
if wdp, ok := hover["workDoneProgress"].(bool); !ok || !wdp {
|
|
t.Fatalf("expected hoverProvider.workDoneProgress=true, got %#v", hover["workDoneProgress"])
|
|
}
|
|
|
|
if decl, ok := decoded.DeclarationProvider.(bool); !ok || !decl {
|
|
t.Fatalf("expected declarationProvider=true, got %#v", decoded.DeclarationProvider)
|
|
}
|
|
|
|
if sem, ok := decoded.SemanticTokensProvider.(map[string]any); !ok || sem["legend"] == nil {
|
|
t.Fatalf("expected semanticTokensProvider.legend, got %#v", decoded.SemanticTokensProvider)
|
|
}
|
|
}
|
|
|
|
func Test_CapabilitiesServer_MarshalExtendedFields(t *testing.T) {
|
|
resolve := true
|
|
original := protocol.ServerCapabilities{
|
|
PositionEncoding: &[]protocol.PositionEncodingKind{protocol.PositionEncodingKindUTF16}[0],
|
|
TextDocumentSync: protocol.TextDocumentSyncOptions{
|
|
OpenClose: true,
|
|
Change: protocol.TextDocumentSyncKindIncremental,
|
|
Save: protocol.SaveOptions{IncludeText: true},
|
|
},
|
|
HoverProvider: protocol.HoverOptions{WorkDoneProgress: true},
|
|
CompletionProvider: &protocol.CompletionOptions{
|
|
ResolveProvider: &resolve,
|
|
CompletionItem: &protocol.CompletionOptionsCompletionItem{
|
|
LabelDetailsSupport: &resolve,
|
|
},
|
|
},
|
|
DeclarationProvider: protocol.DeclarationOptions{WorkDoneProgress: true},
|
|
DefinitionProvider: true,
|
|
CodeActionProvider: protocol.CodeActionOptions{
|
|
CodeActionKinds: []protocol.CodeActionKind{protocol.CodeActionQuickFix},
|
|
ResolveProvider: true,
|
|
},
|
|
CodeLensProvider: &protocol.CodeLensOptions{ResolveProvider: true},
|
|
DocumentLinkProvider: &protocol.DocumentLinkOptions{
|
|
ResolveProvider: true,
|
|
},
|
|
DocumentOnTypeFormattingProvider: &protocol.DocumentOnTypeFormattingOptions{
|
|
FirstTriggerCharacter: ";",
|
|
MoreTriggerCharacter: []string{","},
|
|
},
|
|
RenameProvider: protocol.RenameOptions{PrepareProvider: true},
|
|
ExecuteCommandProvider: &protocol.ExecuteCommandOptions{
|
|
Commands: []string{"laravel.run"},
|
|
},
|
|
SemanticTokensProvider: protocol.SemanticTokensOptions{
|
|
Legend: protocol.SemanticTokensLegend{
|
|
TokenTypes: []string{"class"},
|
|
TokenModifiers: []string{"declaration"},
|
|
},
|
|
Full: true,
|
|
},
|
|
DiagnosticProvider: protocol.DiagnosticOptions{
|
|
InterFileDependencies: true,
|
|
WorkspaceDiagnostics: true,
|
|
},
|
|
WorkspaceSymbolProvider: protocol.WorkspaceSymbolOptions{ResolveProvider: true},
|
|
Workspace: &protocol.WorkspaceServerCapabilities{
|
|
WorkspaceFolders: &protocol.WorkspaceFoldersServerCapabilities{
|
|
Supported: true,
|
|
ChangeNotifications: "workspaceFolders",
|
|
},
|
|
FileOperations: &protocol.FileOperationOptions{
|
|
DidCreate: &protocol.FileOperationRegistrationOptions{
|
|
Filters: []protocol.FileOperationFilter{{
|
|
Scheme: "file",
|
|
Pattern: protocol.FileOperationPattern{
|
|
Glob: "**/*.go",
|
|
},
|
|
}},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
data, err := json.Marshal(original)
|
|
if err != nil {
|
|
t.Fatalf("marshal failed: %v", err)
|
|
}
|
|
|
|
var payload map[string]any
|
|
if err := json.Unmarshal(data, &payload); err != nil {
|
|
t.Fatalf("unmarshal failed: %v", err)
|
|
}
|
|
|
|
if _, ok := payload["textDocumentSync"]; !ok {
|
|
t.Fatalf("expected textDocumentSync in payload: %s", string(data))
|
|
}
|
|
|
|
if _, ok := payload["hoverProvider"]; !ok {
|
|
t.Fatalf("expected hoverProvider in payload: %s", string(data))
|
|
}
|
|
|
|
if _, ok := payload["declarationProvider"]; !ok {
|
|
t.Fatalf("expected declarationProvider in payload: %s", string(data))
|
|
}
|
|
|
|
if _, ok := payload["codeLensProvider"]; !ok {
|
|
t.Fatalf("expected codeLensProvider in payload: %s", string(data))
|
|
}
|
|
|
|
if _, ok := payload["documentOnTypeFormattingProvider"]; !ok {
|
|
t.Fatalf("expected documentOnTypeFormattingProvider in payload: %s", string(data))
|
|
}
|
|
|
|
if _, ok := payload["semanticTokensProvider"]; !ok {
|
|
t.Fatalf("expected semanticTokensProvider in payload: %s", string(data))
|
|
}
|
|
|
|
workspace, ok := payload["workspace"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected workspace object, got %#v", payload["workspace"])
|
|
}
|
|
|
|
if _, ok := workspace["workspaceFolders"]; !ok {
|
|
t.Fatalf("expected workspace.workspaceFolders in payload: %s", string(data))
|
|
}
|
|
|
|
fileOps, ok := workspace["fileOperations"].(map[string]any)
|
|
if !ok {
|
|
t.Fatalf("expected workspace.fileOperations object, got %#v", workspace["fileOperations"])
|
|
}
|
|
|
|
if _, ok := fileOps["didCreate"]; !ok {
|
|
t.Fatalf("expected workspace.fileOperations.didCreate in payload: %s", string(data))
|
|
}
|
|
}
|