zzet--gortex
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
101 行
3.7 KiB
Go
101 行
3.7 KiB
Go
package lsp
|
|
|
|
import (
|
|
"encoding/json"
|
|
"os"
|
|
"path/filepath"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/zzet/gortex/internal/graph"
|
|
"github.com/zzet/gortex/internal/graph/store_sqlite"
|
|
"github.com/zzet/gortex/internal/semantic"
|
|
)
|
|
|
|
// TestLSP_Provider_SkipsAlreadyStampedNodes_LightScan mirrors
|
|
// TestLSP_Provider_SkipsAlreadyStampedNodes but backs the graph with a real
|
|
// sqlite Store, which implements graph.LightNodeReader — exercising the
|
|
// repoScopedNodesLight branch the in-memory-graph test never reaches. The
|
|
// critical extra assertion: a non-promoted meta key present on the fresh
|
|
// node before enrichment must survive the light-scan → candidate refetch
|
|
// (GetNodesByIDs) → hover-stamp → AddBatch round trip. Losing it would mean
|
|
// the light scan's stripped-down Meta got persisted back in place of the
|
|
// full one — silently discarding whatever else the graph had recorded for
|
|
// that node.
|
|
func TestLSP_Provider_SkipsAlreadyStampedNodes_LightScan(t *testing.T) {
|
|
t.Setenv("GORTEX_LSP_SWEEP", "full")
|
|
repoRoot := t.TempDir()
|
|
require.NoError(t, os.WriteFile(
|
|
filepath.Join(repoRoot, "main.go"),
|
|
[]byte("package main\n\nfunc F() string { return \"hi\" }\n\nfunc G() int { return 0 }\n"),
|
|
0o644,
|
|
))
|
|
|
|
var hoverCalls atomic.Int64
|
|
server := newFakeLSPServer()
|
|
server.handle("textDocument/hover", func(params json.RawMessage) (any, *jsonRPCError) {
|
|
hoverCalls.Add(1)
|
|
return map[string]any{
|
|
"contents": map[string]any{"kind": "plaintext", "value": "func G() int"},
|
|
}, nil
|
|
})
|
|
|
|
p, cleanup := providerWithFakeServer(t, server, []string{"go"})
|
|
defer cleanup()
|
|
|
|
g, err := store_sqlite.Open(filepath.Join(t.TempDir(), "enrich.sqlite"))
|
|
require.NoError(t, err)
|
|
defer g.Close()
|
|
var _ graph.LightNodeReader = g // the branch this test targets
|
|
|
|
// F is already stamped by a prior pass — must not be re-hovered.
|
|
g.AddNode(&graph.Node{
|
|
ID: "main.go::F", Kind: graph.KindFunction, Name: "F",
|
|
FilePath: "main.go", StartLine: 3, EndLine: 3, Language: "go",
|
|
Meta: map[string]any{"semantic_type": "func F() string", "semantic_source": "lsp-prior"},
|
|
})
|
|
// G is fresh — must be hovered and stamped. Carries a non-promoted meta
|
|
// key that has nothing to do with enrichment, standing in for whatever
|
|
// else the graph recorded for this node (e.g. a DI-contract tag).
|
|
g.AddNode(&graph.Node{
|
|
ID: "main.go::G", Kind: graph.KindFunction, Name: "G",
|
|
FilePath: "main.go", StartLine: 5, EndLine: 5, Language: "go",
|
|
Meta: map[string]any{"unrelated_tag": "keep-me"},
|
|
})
|
|
|
|
done := make(chan *semantic.EnrichResult, 1)
|
|
go func() {
|
|
res, err := p.Enrich(g, repoRoot)
|
|
require.NoError(t, err)
|
|
done <- res
|
|
}()
|
|
var res *semantic.EnrichResult
|
|
select {
|
|
case res = <-done:
|
|
case <-time.After(3 * time.Second):
|
|
t.Fatal("Enrich timed out")
|
|
}
|
|
|
|
assert.Equal(t, int64(1), hoverCalls.Load(), "only the fresh node is hovered")
|
|
assert.Equal(t, 1, res.HoverCandidates, "post-filter candidate count excludes the stamped node")
|
|
assert.Equal(t, 2, res.SymbolsTotal)
|
|
assert.Equal(t, 2, res.SymbolsCovered)
|
|
|
|
// F keeps its prior stamp (a re-hover would have overwritten it).
|
|
fNode := g.GetNode("main.go::F")
|
|
assert.Equal(t, "func F() string", fNode.Meta["semantic_type"])
|
|
assert.Equal(t, "lsp-prior", fNode.Meta["semantic_source"])
|
|
|
|
// G is now stamped by this pass, AND its pre-existing non-promoted meta
|
|
// key survived the light-scan candidate's full refetch + AddBatch.
|
|
gNode := g.GetNode("main.go::G")
|
|
assert.Equal(t, "func G() int", gNode.Meta["semantic_type"])
|
|
assert.Equal(t, "lsp-fake-lsp", gNode.Meta["semantic_source"])
|
|
assert.Equal(t, "keep-me", gNode.Meta["unrelated_tag"],
|
|
"non-promoted meta present before enrichment must survive the light-scan round trip")
|
|
}
|