github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/internal/lsp/lsp_test.go (about)

     1  package lsp
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/sourcegraph/go-lsp"
     7  	"github.com/stretchr/testify/require"
     8  )
     9  
    10  func TestInitialize(t *testing.T) {
    11  	tester := newLSPTester(t)
    12  	tester.initialize()
    13  }
    14  
    15  func TestAnotherCommandBeforeInitialize(t *testing.T) {
    16  	tester := newLSPTester(t)
    17  
    18  	lerr, serverState := sendAndExpectError(tester, "textDocument/formatting", lsp.FormattingOptions{})
    19  	require.Equal(t, serverStateNotInitialized, serverState)
    20  	require.Equal(t, codeUninitialized, lerr.Code)
    21  }
    22  
    23  func TestDocumentChange(t *testing.T) {
    24  	tester := newLSPTester(t)
    25  	tester.initialize()
    26  
    27  	tester.setFileContents("file:///test", "test")
    28  
    29  	contents, ok := tester.server.files.Get("file:///test")
    30  	require.True(t, ok)
    31  	require.Equal(t, "test", contents.contents)
    32  
    33  	tester.setFileContents("file:///test", "test2")
    34  
    35  	contents, ok = tester.server.files.Get("file:///test")
    36  	require.True(t, ok)
    37  	require.Equal(t, "test2", contents.contents)
    38  }
    39  
    40  func TestDocumentNoDiagnostics(t *testing.T) {
    41  	tester := newLSPTester(t)
    42  	tester.initialize()
    43  
    44  	tester.setFileContents("file:///test", "definition user{}")
    45  
    46  	resp, _ := sendAndReceive[FullDocumentDiagnosticReport](tester, "textDocument/diagnostic",
    47  		TextDocumentDiagnosticParams{
    48  			TextDocument: TextDocument{URI: "file:///test"},
    49  		})
    50  	require.Equal(t, "full", resp.Kind)
    51  	require.Len(t, resp.Items, 0)
    52  }
    53  
    54  func TestDocumentErrorDiagnostics(t *testing.T) {
    55  	tester := newLSPTester(t)
    56  	tester.initialize()
    57  
    58  	tester.setFileContents("file:///test", "test")
    59  
    60  	resp, _ := sendAndReceive[FullDocumentDiagnosticReport](tester, "textDocument/diagnostic",
    61  		TextDocumentDiagnosticParams{
    62  			TextDocument: TextDocument{URI: "file:///test"},
    63  		})
    64  	require.Equal(t, "full", resp.Kind)
    65  	require.Len(t, resp.Items, 1)
    66  	require.Equal(t, lsp.Error, resp.Items[0].Severity)
    67  	require.Equal(t, "Unexpected token at root level: TokenTypeIdentifier", resp.Items[0].Message)
    68  	require.Equal(t, lsp.Range{
    69  		Start: lsp.Position{Line: 0, Character: 0},
    70  		End:   lsp.Position{Line: 0, Character: 0},
    71  	}, resp.Items[0].Range)
    72  
    73  	tester.setFileContents("file:///test", "definition user{}")
    74  
    75  	resp, _ = sendAndReceive[FullDocumentDiagnosticReport](tester, "textDocument/diagnostic",
    76  		TextDocumentDiagnosticParams{
    77  			TextDocument: TextDocument{URI: "file:///test"},
    78  		})
    79  	require.Equal(t, "full", resp.Kind)
    80  	require.Len(t, resp.Items, 0)
    81  }
    82  
    83  func TestDocumentWarningDiagnostics(t *testing.T) {
    84  	tester := newLSPTester(t)
    85  	tester.initialize()
    86  
    87  	tester.setFileContents("file:///test", `
    88  		definition user {}
    89  
    90  		definition resource {
    91  			relation viewer: user
    92  			permission view_resource = viewer
    93  		}
    94  	`)
    95  
    96  	resp, _ := sendAndReceive[FullDocumentDiagnosticReport](tester, "textDocument/diagnostic",
    97  		TextDocumentDiagnosticParams{
    98  			TextDocument: TextDocument{URI: "file:///test"},
    99  		})
   100  	require.Equal(t, "full", resp.Kind)
   101  	require.Len(t, resp.Items, 1)
   102  	require.Equal(t, lsp.DiagnosticSeverity(lsp.Warning), resp.Items[0].Severity)
   103  	require.Equal(t, `Permission "view_resource" references parent type "resource" in its name; it is recommended to drop the suffix`, resp.Items[0].Message)
   104  	require.Equal(t, lsp.Range{
   105  		Start: lsp.Position{Line: 5, Character: 3},
   106  		End:   lsp.Position{Line: 5, Character: 3},
   107  	}, resp.Items[0].Range)
   108  }
   109  
   110  func TestDocumentDiagnosticsForTypeError(t *testing.T) {
   111  	tester := newLSPTester(t)
   112  	tester.initialize()
   113  
   114  	tester.setFileContents("file:///test", `definition user {}
   115  
   116  	definition resource {
   117  		relation foo: something
   118  	}
   119  `)
   120  
   121  	resp, _ := sendAndReceive[FullDocumentDiagnosticReport](tester, "textDocument/diagnostic",
   122  		TextDocumentDiagnosticParams{
   123  			TextDocument: TextDocument{URI: "file:///test"},
   124  		})
   125  	require.Equal(t, "full", resp.Kind)
   126  	require.Len(t, resp.Items, 1)
   127  	require.Equal(t, lsp.Error, resp.Items[0].Severity)
   128  	require.Contains(t, resp.Items[0].Message, "object definition `something` not found")
   129  	require.Equal(t, lsp.Range{
   130  		Start: lsp.Position{Line: 3, Character: 16},
   131  		End:   lsp.Position{Line: 3, Character: 16},
   132  	}, resp.Items[0].Range)
   133  }
   134  
   135  func TestDocumentFormat(t *testing.T) {
   136  	tester := newLSPTester(t)
   137  	tester.initialize()
   138  
   139  	tester.setFileContents("file:///test", "definition user{}")
   140  
   141  	resp, _ := sendAndReceive[[]lsp.TextEdit](tester, "textDocument/formatting",
   142  		lsp.DocumentFormattingParams{
   143  			TextDocument: lsp.TextDocumentIdentifier{URI: "file:///test"},
   144  		})
   145  	require.Len(t, resp, 1)
   146  	require.Equal(t, lsp.Range{
   147  		Start: lsp.Position{Line: 0, Character: 0},
   148  		End:   lsp.Position{Line: 10000000, Character: 100000000},
   149  	}, resp[0].Range)
   150  	require.Equal(t, "definition user {}", resp[0].NewText)
   151  }
   152  
   153  func TestDocumentOpenedClosed(t *testing.T) {
   154  	tester := newLSPTester(t)
   155  	tester.initialize()
   156  
   157  	sendAndReceive[any](tester, "textDocument/didOpen", lsp.DidOpenTextDocumentParams{
   158  		TextDocument: lsp.TextDocumentItem{
   159  			URI:        lsp.DocumentURI("file:///test"),
   160  			LanguageID: "test",
   161  			Version:    1,
   162  			Text:       "definition user{}",
   163  		},
   164  	})
   165  
   166  	contents, ok := tester.server.files.Get(lsp.DocumentURI("file:///test"))
   167  	require.True(t, ok)
   168  	require.Equal(t, "definition user{}", contents.contents)
   169  
   170  	sendAndReceive[any](tester, "textDocument/didClose", lsp.DidCloseTextDocumentParams{
   171  		TextDocument: lsp.TextDocumentIdentifier{
   172  			URI: lsp.DocumentURI("file:///test"),
   173  		},
   174  	})
   175  
   176  	_, ok = tester.server.files.Get(lsp.DocumentURI("file:///test"))
   177  	require.False(t, ok)
   178  }
   179  
   180  func TestDocumentHover(t *testing.T) {
   181  	tester := newLSPTester(t)
   182  	tester.initialize()
   183  
   184  	sendAndReceive[any](tester, "textDocument/didOpen", lsp.DidOpenTextDocumentParams{
   185  		TextDocument: lsp.TextDocumentItem{
   186  			URI:        lsp.DocumentURI("file:///test"),
   187  			LanguageID: "test",
   188  			Version:    1,
   189  			Text: `definition user {}
   190  
   191  definition resource {
   192  	relation viewer: user
   193  }
   194  `,
   195  		},
   196  	})
   197  
   198  	resp, _ := sendAndReceive[Hover](tester, "textDocument/hover", lsp.TextDocumentPositionParams{
   199  		TextDocument: lsp.TextDocumentIdentifier{
   200  			URI: lsp.DocumentURI("file:///test"),
   201  		},
   202  		Position: lsp.Position{Line: 3, Character: 18},
   203  	})
   204  
   205  	require.Equal(t, "definition user {}", resp.Contents.Value)
   206  	require.Equal(t, "spicedb", resp.Contents.Language)
   207  }