a06f331eb8
CI / benchmark (push) Has been skipped
install-script / posix-syntax (push) Successful in 6m1s
CI / build-onnx (push) Failing after 6m43s
init-smoke / dry-run (push) Failing after 15m57s
security / govulncheck (push) Has been cancelled
security / trivy-fs (push) Has been cancelled
CI / test (1.26, ubuntu-latest) (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
CI / test (1.26, macos-latest) (push) Has been cancelled
CI / build-windows (push) Has been cancelled
CI / lint (push) Has been cancelled
install-script / powershell-syntax (push) Has been cancelled
install-script / install (macos-14) (push) Has been cancelled
install-script / install (ubuntu-latest) (push) Has been cancelled
99 lines
3.8 KiB
Go
99 lines
3.8 KiB
Go
package lsp
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
)
|
|
|
|
// TestLSP_Enrich_SkipsFilesOutsideProviderCoverage pins that enrichment never
|
|
// sends a language server a file its ServerSpec does not cover. An ambiguous
|
|
// edge whose referent lives in an asset file (a `.png`) must not cause a
|
|
// didOpen / references round trip against a C/C++ server, which would otherwise
|
|
// try to build an AST with an inferred compile command and churn on invalid
|
|
// ASTs for zero graph signal.
|
|
func TestLSP_Enrich_SkipsFilesOutsideProviderCoverage(t *testing.T) {
|
|
repoRoot := t.TempDir()
|
|
require.NoError(t, os.WriteFile(filepath.Join(repoRoot, "main.c"),
|
|
[]byte("void caller(void) {\n helper();\n useImg();\n}\n"), 0o644))
|
|
require.NoError(t, os.WriteFile(filepath.Join(repoRoot, "def.c"),
|
|
[]byte("void helper(void) {}\n"), 0o644))
|
|
// logo.png is deliberately NOT written — the guard must skip it before any
|
|
// os.ReadFile / didOpen.
|
|
|
|
server := newInstrumentedServer()
|
|
var reqMu sync.Mutex
|
|
reqURIs := map[string]bool{}
|
|
recordReq := func(params json.RawMessage) {
|
|
var req struct {
|
|
TextDocument struct {
|
|
URI string `json:"uri"`
|
|
} `json:"textDocument"`
|
|
}
|
|
_ = json.Unmarshal(params, &req)
|
|
reqMu.Lock()
|
|
reqURIs[req.TextDocument.URI] = true
|
|
reqMu.Unlock()
|
|
}
|
|
for _, m := range []string{
|
|
"textDocument/references", "textDocument/hover",
|
|
"textDocument/prepareCallHierarchy", "textDocument/prepareTypeHierarchy",
|
|
"textDocument/implementation", "textDocument/definition",
|
|
} {
|
|
server.handle(m, func(params json.RawMessage) (any, *jsonRPCError) {
|
|
recordReq(params)
|
|
return []Location{}, nil
|
|
})
|
|
}
|
|
|
|
p, cleanup := providerWithInstrumentedServer(t, server, []string{"c", "cpp"}, 2)
|
|
defer cleanup()
|
|
// Scope the provider to C/C++ extensions, as the registry does for clangd.
|
|
p.spec = &ServerSpec{
|
|
Name: "clangd",
|
|
Languages: []string{"c", "cpp"},
|
|
Extensions: []string{".c", ".h", ".cpp", ".hpp"},
|
|
}
|
|
|
|
g := graph.New()
|
|
g.AddNode(&graph.Node{ID: "main.c::caller", Kind: graph.KindFunction, Name: "caller",
|
|
FilePath: "main.c", StartLine: 1, EndLine: 4, Language: "c"})
|
|
g.AddNode(&graph.Node{ID: "def.c::helper", Kind: graph.KindFunction, Name: "helper",
|
|
FilePath: "def.c", StartLine: 1, EndLine: 1, Language: "c"})
|
|
// A mis-tagged asset node (Language "c") — the shape that leaked .png files
|
|
// to clangd. It is both an ambiguous-edge referent and a would-be hover
|
|
// target, so both open paths must skip it.
|
|
g.AddNode(&graph.Node{ID: "logo.png::img", Kind: graph.KindFunction, Name: "img",
|
|
FilePath: "logo.png", StartLine: 1, EndLine: 1, Language: "c"})
|
|
g.AddEdge(&graph.Edge{From: "main.c::caller", To: "def.c::helper", Kind: graph.EdgeCalls,
|
|
FilePath: "main.c", Line: 2, Confidence: 0.7, ConfidenceLabel: "INFERRED", Origin: graph.OriginTextMatched})
|
|
g.AddEdge(&graph.Edge{From: "main.c::caller", To: "logo.png::img", Kind: graph.EdgeCalls,
|
|
FilePath: "main.c", Line: 3, Confidence: 0.7, ConfidenceLabel: "INFERRED", Origin: graph.OriginTextMatched})
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
|
defer cancel()
|
|
_, err := p.EnrichRepoContext(ctx, g, "", repoRoot, nil)
|
|
require.NoError(t, err)
|
|
|
|
pngURI := pathToURI(filepath.Join(repoRoot, "logo.png"))
|
|
defURI := pathToURI(filepath.Join(repoRoot, "def.c"))
|
|
|
|
assert.False(t, server.wasOpened(pngURI), "asset file must never be opened on the C/C++ server")
|
|
reqMu.Lock()
|
|
assert.False(t, reqURIs[pngURI], "no LSP request may target the asset file")
|
|
reqMu.Unlock()
|
|
|
|
// The guard is selective, not a blanket skip: served C files are still
|
|
// opened and queried.
|
|
assert.True(t, server.wasOpened(defURI), "a covered .c referent must still be opened")
|
|
}
|