From 38594832c7e9c69c811247e20052faa1cdbcc63d Mon Sep 17 00:00:00 2001 From: zerunz Date: Mon, 3 Nov 2025 23:54:17 +0000 Subject: [PATCH 1/5] chore(scip-registry) Replace ulsp/controller/scip partialScipRegistry with the scip-lib/registry one --- src/scip-lib/registry/BUILD.bazel | 27 +++ .../registry/registrymock/BUILD.bazel | 1 + src/scip-lib/registry/registrymock/dummy.go | 1 + src/ulsp/controller/scip/BUILD.bazel | 3 + src/ulsp/controller/scip/scip.go | 11 +- src/ulsp/controller/scip/scip_test.go | 208 +++++++++--------- 6 files changed, 143 insertions(+), 108 deletions(-) create mode 100644 src/scip-lib/registry/registrymock/BUILD.bazel create mode 100644 src/scip-lib/registry/registrymock/dummy.go diff --git a/src/scip-lib/registry/BUILD.bazel b/src/scip-lib/registry/BUILD.bazel index 685f89d..5029569 100644 --- a/src/scip-lib/registry/BUILD.bazel +++ b/src/scip-lib/registry/BUILD.bazel @@ -1,3 +1,4 @@ +load("@bazel_gomock//rules:gomock.bzl", "gomock") load("@rules_go//go:def.bzl", "go_library", "go_test") go_library( @@ -20,6 +21,32 @@ go_library( ], ) +gomock( + name = "registrymock", + out = "registry_mock_for_test.go", + interfaces = [ + "Registry", + ], + library = ":go_default_library", + mockgen_tool = "@org_uber_go_mock//mockgen", + package = "registrymock", + self_package = "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock", +) + +go_library( + name = "go_registry_gomock_library", + srcs = [":registrymock"], + importpath = "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock", + visibility = ["//visibility:public"], + deps = [ + ":go_default_library", + "//src/scip-lib/model:go_default_library", + "@dev_lsp_go_protocol//:go_default_library", + "@dev_lsp_go_uri//:go_default_library", + "@org_uber_go_mock//gomock:go_default_library", + ], +) + go_test( name = "go_default_test", srcs = ["partial_registry_test.go"], diff --git a/src/scip-lib/registry/registrymock/BUILD.bazel b/src/scip-lib/registry/registrymock/BUILD.bazel new file mode 100644 index 0000000..137d8b9 --- /dev/null +++ b/src/scip-lib/registry/registrymock/BUILD.bazel @@ -0,0 +1 @@ +# gazelle:exclude dummy.go diff --git a/src/scip-lib/registry/registrymock/dummy.go b/src/scip-lib/registry/registrymock/dummy.go new file mode 100644 index 0000000..767b91e --- /dev/null +++ b/src/scip-lib/registry/registrymock/dummy.go @@ -0,0 +1 @@ +package dummy diff --git a/src/ulsp/controller/scip/BUILD.bazel b/src/ulsp/controller/scip/BUILD.bazel index e078823..dd87cb4 100644 --- a/src/ulsp/controller/scip/BUILD.bazel +++ b/src/ulsp/controller/scip/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "//src/scip-lib/mapper:go_default_library", "//src/scip-lib/model:go_default_library", "//src/scip-lib/partialloader:go_default_library", + "//src/scip-lib/registry:go_default_library", "//src/ulsp/controller/diagnostics:go_default_library", "//src/ulsp/controller/doc-sync:go_default_library", "//src/ulsp/entity:go_default_library", @@ -59,6 +60,8 @@ go_test( "//src/scip-lib/mapper:go_default_library", "//src/scip-lib/model:go_default_library", "//src/scip-lib/partialloader:go_loader_gomock_library", + "//src/scip-lib/registry:go_default_library", + "//src/scip-lib/registry:go_registry_gomock_library", "//src/ulsp/controller/diagnostics:go_diagnostics_gomock_library", "//src/ulsp/controller/doc-sync:go_default_library", "//src/ulsp/controller/doc-sync:go_docsync_gomock_library", diff --git a/src/ulsp/controller/scip/scip.go b/src/ulsp/controller/scip/scip.go index bd62b8a..bd0c7c4 100644 --- a/src/ulsp/controller/scip/scip.go +++ b/src/ulsp/controller/scip/scip.go @@ -18,6 +18,7 @@ import ( ulspplugin "github.com/uber/scip-lsp/src/ulsp/entity/ulsp-plugin" ideclient "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client" "github.com/uber/scip-lsp/src/ulsp/internal/fs" + "github.com/uber/scip-lsp/src/scip-lib/registry" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" ulsp_mapper "github.com/uber/scip-lsp/src/ulsp/mapper" "github.com/uber/scip-lsp/src/ulsp/repository/session" @@ -67,7 +68,7 @@ type controller struct { stats tally.Scope documents docsync.Controller diagnostics diagnostics.Controller - registries map[string]Registry + registries map[string]registry.Registry registriesMu sync.Mutex watcher *fsnotify.Watcher once sync.Once @@ -75,7 +76,7 @@ type controller struct { initialLoad chan bool watchCloser chan bool loadedIndices map[string]string - newScipRegistry func(workspaceRoot, indexFolder string) Registry + newScipRegistry func(workspaceRoot, indexFolder string) registry.Registry debounceTimers map[string]*time.Timer debounceMu sync.Mutex indexNotifier *IndexNotifier @@ -107,7 +108,7 @@ func New(p Params) (Controller, error) { stats: p.Stats.SubScope("scip"), documents: p.PluginDocSync, diagnostics: p.PluginDiagnostics, - registries: make(map[string]Registry), + registries: make(map[string]registry.Registry), watcher: watcher, fs: p.FS, initialLoad: make(chan bool, 1), @@ -115,14 +116,14 @@ func New(p Params) (Controller, error) { loadedIndices: make(map[string]string), debounceTimers: make(map[string]*time.Timer), indexNotifier: NewIndexNotifier(notifier.NewNotificationManager(notificationManagerParams)), - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { p.Logger.Infof("Creating new SCIP registry for %q, index folder %q", workspaceRoot, indexFolder) return NewPartialScipRegistry(workspaceRoot, indexFolder, p.Logger.Named("fast-loader")) }, }, nil } -func (c *controller) createNewScipRegistry(workspaceRoot string, monorepo entity.MonorepoName) Registry { +func (c *controller) createNewScipRegistry(workspaceRoot string, monorepo entity.MonorepoName) registry.Registry { indexFolder := path.Join(workspaceRoot, ".scip") if len(c.configs[monorepo].Scip.Directories) > 0 { indexFolder = path.Join(workspaceRoot, c.configs["_default"].Scip.Directories[0]) diff --git a/src/ulsp/controller/scip/scip_test.go b/src/ulsp/controller/scip/scip_test.go index 0a8245b..036d5f1 100644 --- a/src/ulsp/controller/scip/scip_test.go +++ b/src/ulsp/controller/scip/scip_test.go @@ -23,6 +23,8 @@ import ( "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync/docsyncmock" "github.com/uber/scip-lsp/src/ulsp/entity" "github.com/uber/scip-lsp/src/ulsp/factory" + "github.com/uber/scip-lsp/src/scip-lib/registry" + "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock" "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client/ideclientmock" "github.com/uber/scip-lsp/src/ulsp/internal/fs/fsmock" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" @@ -112,8 +114,8 @@ func TestInitialize(t *testing.T) { dir := t.TempDir() scipDir := path.Join(dir, ".scip") - newScipCtl := func(fs *fsmock.MockUlspFS, reg *MockRegistry, monorepo entity.MonorepoName, loadFromDir bool, sessionFail bool, createScipDir bool) controller { - regs := map[string]Registry{} + newScipCtl := func(fs *fsmock.MockUlspFS, reg *registrymock.MockRegistry, monorepo entity.MonorepoName, loadFromDir bool, sessionFail bool, createScipDir bool) controller { + regs := map[string]registry.Registry{} s.Monorepo = monorepo s.WorkspaceRoot = dir @@ -148,7 +150,7 @@ func TestInitialize(t *testing.T) { watchCloser: make(chan bool), initialLoad: make(chan bool, 1), loadedIndices: make(map[string]string), - newScipRegistry: func(workspaceRoot string, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot string, indexFolder string) registry.Registry { return reg }, indexNotifier: NewIndexNotifier(notMgrMock), @@ -158,7 +160,7 @@ func TestInitialize(t *testing.T) { t.Run("not enabled", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) fsMock := fsmock.NewMockUlspFS(ctrl) c := newScipCtl(fsMock, regMock, _monorepoNameJava, false, false, true) @@ -174,7 +176,7 @@ func TestInitialize(t *testing.T) { t.Run("no scip files", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) fsMock := fsmock.NewMockUlspFS(ctrl) @@ -194,7 +196,7 @@ func TestInitialize(t *testing.T) { t.Run("failed to add watcher", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) fsMock := fsmock.NewMockUlspFS(ctrl) fsMock.EXPECT().MkdirAll(gomock.Any()).Return(errors.New("failed")) @@ -210,7 +212,7 @@ func TestInitialize(t *testing.T) { t.Run("failed to create scip dir", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) fsMock := fsmock.NewMockUlspFS(ctrl) fsMock.EXPECT().MkdirAll(gomock.Any()).Return(errors.New("failed to create scip dir")) @@ -226,7 +228,7 @@ func TestInitialize(t *testing.T) { t.Run("with scip files", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) regMock.EXPECT().LoadIndexFile(gomock.Any()).Return(nil) @@ -251,7 +253,7 @@ func TestInitialize(t *testing.T) { t.Run("file open error doesn't fail", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().LoadIndexFile(gomock.Any()).Return(errors.New("file not found")) @@ -276,7 +278,7 @@ func TestInitialize(t *testing.T) { t.Run("LoadIndex error doesn't fail", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().LoadIndexFile(gomock.Any()).Return(errors.New("invalid scip file")) @@ -301,7 +303,7 @@ func TestInitialize(t *testing.T) { t.Run("ReadDir error doesn't fail", func(t *testing.T) { ctrl := gomock.NewController(t) - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) fsMock := fsmock.NewMockUlspFS(ctrl) fsMock.EXPECT().MkdirAll(gomock.Any()).Return(nil) @@ -326,7 +328,7 @@ func TestInitialize(t *testing.T) { NewMockDirEntry("sample.scip"), }, nil) fsMock.EXPECT().ReadFile(gomock.Any()).Return([]byte("sampleSha"), nil) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockReg.EXPECT().SetDocumentLoadedCallback(gomock.Any()) mockReg.EXPECT().LoadConcurrency().Return(1) mockReg.EXPECT().LoadIndexFile(gomock.Any()).Return(nil) @@ -387,8 +389,8 @@ func TestGotoDeclaration(t *testing.T) { assert.NoError(t, err) } -func getMockedController(t *testing.T, ctrl *gomock.Controller) (controller, *MockRegistry) { - reg := NewMockRegistry(ctrl) +func getMockedController(t *testing.T, ctrl *gomock.Controller) (controller, *registrymock.MockRegistry) { + reg := registrymock.NewMockRegistry(ctrl) s := &entity.Session{ UUID: factory.UUID(), } @@ -397,7 +399,7 @@ func getMockedController(t *testing.T, ctrl *gomock.Controller) (controller, *Mo sessionRepository.EXPECT().GetFromContext(gomock.Any()).Return(s, nil).AnyTimes() return controller{ - registries: map[string]Registry{ + registries: map[string]registry.Registry{ "/some/path": reg, }, sessions: sessionRepository, @@ -438,13 +440,13 @@ func TestGotoDefinition(t *testing.T) { tests := []struct { name string - setupMocks func(t *testing.T, c *controller, reg *MockRegistry) + setupMocks func(t *testing.T, c *controller, reg *registrymock.MockRegistry) expected []protocol.LocationLink expectedErr error }{ { name: "no symbol data", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, bool, error) { return pos, false, nil @@ -459,7 +461,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "has error return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, bool, error) { return pos, false, nil @@ -475,7 +477,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "has location", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, bool, error) { return pos, false, nil @@ -519,7 +521,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "nil definition occurrence", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, bool, error) { return pos, false, nil @@ -561,7 +563,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "shifted position in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { @@ -589,7 +591,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "new position in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, true, nil) documents := docsyncmock.NewMockController(ctrl) @@ -600,7 +602,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "shifted position error", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{}, false, errors.New("test error")) documents := docsyncmock.NewMockController(ctrl) @@ -612,7 +614,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "shifted position in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) @@ -648,7 +650,7 @@ func TestGotoDefinition(t *testing.T) { }, { name: "shifted position errors in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) @@ -712,13 +714,13 @@ func TestDocumentSymbol(t *testing.T) { tests := []struct { name string - setupMocks func(t *testing.T, c *controller, reg *MockRegistry) + setupMocks func(t *testing.T, c *controller, reg *registrymock.MockRegistry) expected []protocol.DocumentSymbol expectedErr error }{ { name: "empty symbol", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { return pos, nil @@ -733,7 +735,7 @@ func TestDocumentSymbol(t *testing.T) { }, { name: "has error return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { return pos, nil @@ -748,7 +750,7 @@ func TestDocumentSymbol(t *testing.T) { }, { name: "has symbol", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { return pos, nil @@ -800,7 +802,7 @@ func TestDocumentSymbol(t *testing.T) { }, { name: "shifted symbol positions in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) // Mock position mapping to shift positions by 10 lines and 5 characters positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { @@ -856,7 +858,7 @@ func TestDocumentSymbol(t *testing.T) { }, { name: "position mapping errors in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapBasePositionToCurrent(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, error) { return protocol.Position{}, errors.New("failed to map position") @@ -937,11 +939,11 @@ func TestHover(t *testing.T) { name string expected *protocol.Hover expectedErr error - setupMocks func(t *testing.T, c *controller, reg *MockRegistry) + setupMocks func(t *testing.T, c *controller, reg *registrymock.MockRegistry) }{ { name: "no symbol data", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 0, Character: 0}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -954,7 +956,7 @@ func TestHover(t *testing.T) { }, { name: "has error return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 0, Character: 0}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -968,7 +970,7 @@ func TestHover(t *testing.T) { }, { name: "normal return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 0, Character: 0}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1001,7 +1003,7 @@ func TestHover(t *testing.T) { }, { name: "shifted position in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1034,7 +1036,7 @@ func TestHover(t *testing.T) { }, { name: "shifted position in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).DoAndReturn(func(pos protocol.Position) (protocol.Position, bool, error) { return pos, false, nil @@ -1068,7 +1070,7 @@ func TestHover(t *testing.T) { }, { name: "new position", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, true, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1079,7 +1081,7 @@ func TestHover(t *testing.T) { }, { name: "shifted position error", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{}, false, errors.New("test error")) documents := docsyncmock.NewMockController(ctrl) @@ -1140,13 +1142,13 @@ func TestReferences(t *testing.T) { tests := []struct { name string - setupMocks func(t *testing.T, c *controller, reg *MockRegistry) + setupMocks func(t *testing.T, c *controller, reg *registrymock.MockRegistry) expected []protocol.Location expectedErr error }{ { name: "no references", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 1, Character: 1}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1159,7 +1161,7 @@ func TestReferences(t *testing.T) { }, { name: "has error return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 1, Character: 1}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1173,7 +1175,7 @@ func TestReferences(t *testing.T) { }, { name: "normal return", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 1, Character: 1}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1199,7 +1201,7 @@ func TestReferences(t *testing.T) { }, { name: "shifted symbol in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1225,7 +1227,7 @@ func TestReferences(t *testing.T) { }, { name: "new position in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, true, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1236,7 +1238,7 @@ func TestReferences(t *testing.T) { }, { name: "shifted symbol in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1261,7 +1263,7 @@ func TestReferences(t *testing.T) { }, { name: "shifted position error in request", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{}, false, errors.New("test error")) documents := docsyncmock.NewMockController(ctrl) @@ -1273,7 +1275,7 @@ func TestReferences(t *testing.T) { }, { name: "shifted position errors in response", - setupMocks: func(t *testing.T, c *controller, reg *MockRegistry) { + setupMocks: func(t *testing.T, c *controller, reg *registrymock.MockRegistry) { positionMapper := docsyncmock.NewMockPositionMapper(ctrl) positionMapper.EXPECT().MapCurrentPositionToBase(gomock.Any()).Return(protocol.Position{Line: 2, Character: 2}, false, nil) documents := docsyncmock.NewMockController(ctrl) @@ -1345,7 +1347,7 @@ func TestIndexReloading(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotMgr.EXPECT().StartNotification(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("No notifier")) @@ -1356,13 +1358,13 @@ func TestIndexReloading(t *testing.T) { operationDone := make(chan struct{}) c := &controller{ - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), fs: mockFs, watcher: w, loadedIndices: make(map[string]string), debounceTimers: make(map[string]*time.Timer), - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1406,7 +1408,7 @@ func TestIndexReloading(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotMgr.EXPECT().StartNotification(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("No notifier")) @@ -1417,13 +1419,13 @@ func TestIndexReloading(t *testing.T) { operationDone := make(chan struct{}) c := &controller{ - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), fs: mockFs, watcher: w, loadedIndices: make(map[string]string), debounceTimers: make(map[string]*time.Timer), - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1477,7 +1479,7 @@ func TestIndexReloading(t *testing.T) { mockFs := fsmock.NewMockUlspFS(ctrl) mockFs.EXPECT().ReadFile(gomock.Any()).Return([]byte("sampleSha"), nil).AnyTimes() - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockReg.EXPECT().LoadIndexFile(gomock.Any()).Return(nil).AnyTimes() mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotMgr.EXPECT().StartNotification(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil, errors.New("No notifier")) @@ -1487,13 +1489,13 @@ func TestIndexReloading(t *testing.T) { assert.NoError(t, err) c := &controller{ - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), fs: mockFs, watcher: w, loadedIndices: make(map[string]string), debounceTimers: make(map[string]*time.Timer), - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1530,7 +1532,7 @@ func TestIndexReloading(t *testing.T) { mockFs.EXPECT().ReadFile(gomock.Any()).DoAndReturn(func(arg interface{}) ([]byte, error) { return []byte("sampleSha"), nil }).Times(1) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotHndlr := notifiermock.NewMockNotificationHandler(ctrl) mockNotHndlr.EXPECT().Done(gomock.Any()).DoAndReturn(func(ctx context.Context) bool { @@ -1568,7 +1570,7 @@ func TestIndexReloading(t *testing.T) { }, }}, sessions: sessionRepository, - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), initialLoad: make(chan bool, 1), fs: mockFs, @@ -1576,7 +1578,7 @@ func TestIndexReloading(t *testing.T) { loadedIndices: make(map[string]string), diagnostics: diagnostics, documents: documents, - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, debounceTimers: make(map[string]*time.Timer), @@ -1621,7 +1623,7 @@ func TestHandleChangesErrorConfig(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) sampleWorkspaceRoot := path.Join("/sample/home/", string(_monorepoNameJava)) sessionRepository := repositorymock.NewMockRepository(ctrl) s := &entity.Session{ @@ -1638,7 +1640,7 @@ func TestHandleChangesErrorConfig(t *testing.T) { c := &controller{ configs: map[entity.MonorepoName]entity.MonorepoConfigEntry{}, sessions: sessionRepository, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ dir: mockReg, }, logger: zap.NewNop().Sugar(), @@ -1670,7 +1672,7 @@ func TestHandleChangesErrorSessionsObject(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) sampleWorkspaceRoot := path.Join("/sample/home/", string(_monorepoNameJava)) sessionRepository := repositorymock.NewMockRepository(ctrl) s := &entity.Session{ @@ -1687,7 +1689,7 @@ func TestHandleChangesErrorSessionsObject(t *testing.T) { c := &controller{ configs: map[entity.MonorepoName]entity.MonorepoConfigEntry{}, sessions: sessionRepository, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ dir: mockReg, }, logger: zap.NewNop().Sugar(), @@ -1731,7 +1733,7 @@ func TestNotifier(t *testing.T) { fsMock := fsmock.NewMockUlspFS(ctrl) fsMock.EXPECT().ReadDir(gomock.Any()).Return([]os.DirEntry{}, nil) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockReg.EXPECT().LoadConcurrency().Return(1) mockReg.EXPECT().SetDocumentLoadedCallback(gomock.Any()) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) @@ -1746,12 +1748,12 @@ func TestNotifier(t *testing.T) { }, }}, sessions: sessionRepository, - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), initialLoad: make(chan bool, 1), fs: fsMock, loadedIndices: make(map[string]string), - newScipRegistry: func(workspaceRoot string, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot string, indexFolder string) registry.Registry { return mockReg }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1775,7 +1777,7 @@ func TestNotifier(t *testing.T) { s.Monorepo = _monorepoNameJava sessionRepository.EXPECT().GetFromContext(gomock.Any()).Return(s, nil).AnyTimes() - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().LoadIndexFile(gomock.Any()).Return(nil) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) @@ -1803,12 +1805,12 @@ func TestNotifier(t *testing.T) { }, }}, sessions: sessionRepository, - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), initialLoad: make(chan bool, 1), fs: fsMock, loadedIndices: make(map[string]string), - newScipRegistry: func(workspaceRoot string, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot string, indexFolder string) registry.Registry { return regMock }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1831,7 +1833,7 @@ func TestNotifier(t *testing.T) { s.WorkspaceRoot = sampleWorkspaceRoot sessionRepository.EXPECT().GetFromContext(gomock.Any()).Return(s, nil).AnyTimes() - regMock := NewMockRegistry(ctrl) + regMock := registrymock.NewMockRegistry(ctrl) regMock.EXPECT().LoadConcurrency().Return(1) regMock.EXPECT().SetDocumentLoadedCallback(gomock.Any()) regMock.EXPECT().LoadIndexFile(gomock.Any()).Return(errors.New("failed to open")) @@ -1861,12 +1863,12 @@ func TestNotifier(t *testing.T) { }, }}, sessions: sessionRepository, - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), initialLoad: make(chan bool, 1), fs: fsMock, ideGateway: mockGateway, - newScipRegistry: func(workspaceRoot string, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot string, indexFolder string) registry.Registry { return regMock }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -1884,7 +1886,7 @@ func TestNotifier(t *testing.T) { mockFs := fsmock.NewMockUlspFS(ctrl) mockFs.EXPECT().ReadFile(gomock.Any()).Return([]byte("sampleSha"), nil) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotHndlr := notifiermock.NewMockNotificationHandler(ctrl) mockNotHndlr.EXPECT().Done(gomock.Any()).DoAndReturn(func(ctx context.Context) bool { @@ -1921,7 +1923,7 @@ func TestNotifier(t *testing.T) { }, }}, sessions: sessionRepository, - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, logger: zap.NewNop().Sugar(), initialLoad: make(chan bool, 1), fs: mockFs, @@ -1929,7 +1931,7 @@ func TestNotifier(t *testing.T) { loadedIndices: make(map[string]string), diagnostics: diagnostics, documents: documents, - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, debounceTimers: make(map[string]*time.Timer), @@ -1992,7 +1994,7 @@ func TestNotifier(t *testing.T) { mockFs.EXPECT().ReadFile(gomock.Any()).DoAndReturn(func(arg interface{}) ([]byte, error) { return []byte("sampleSha"), nil }) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) mockNotMgr := notifiermock.NewMockNotificationManager(ctrl) mockNotHndlr := notifiermock.NewMockNotificationHandler(ctrl) mockNotHndlr.EXPECT().Done(gomock.Any()).Return() @@ -2034,7 +2036,7 @@ func TestNotifier(t *testing.T) { }, }, }}, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ dir: mockReg, }, sessions: sessionRepository, @@ -2047,7 +2049,7 @@ func TestNotifier(t *testing.T) { diagnostics: diagnostics, documents: documents, debounceTimers: make(map[string]*time.Timer), - newScipRegistry: func(workspaceRoot, indexFolder string) Registry { + newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { return mockReg }, indexNotifier: NewIndexNotifier(mockNotMgr), @@ -2089,7 +2091,7 @@ func TestGetSha(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) dir := t.TempDir() sampleWorkspaceRoot := path.Join(dir, string(_monorepoNameJava)) @@ -2108,7 +2110,7 @@ func TestGetSha(t *testing.T) { }, }, }}, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ sampleWorkspaceRoot: mockReg, }, logger: zap.NewNop().Sugar(), @@ -2130,7 +2132,7 @@ func TestGetSha(t *testing.T) { ctrl := gomock.NewController(t) mockFs := fsmock.NewMockUlspFS(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) dir := t.TempDir() sampleWorkspaceRoot := path.Join(dir, string(_monorepoNameJava)) @@ -2149,7 +2151,7 @@ func TestGetSha(t *testing.T) { }, }, }}, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ sampleWorkspaceRoot: mockReg, }, logger: zap.NewNop().Sugar(), @@ -2175,7 +2177,7 @@ func TestControllerGetDocumentSymbols(t *testing.T) { uri string sessionErr error overrideWSR string - registry Registry + registry registry.Registry expected []*model.SymbolOccurrence expectedErr error }{ @@ -2198,8 +2200,8 @@ func TestControllerGetDocumentSymbols(t *testing.T) { name: "registry returns document symbols", uri: "file:///test.go", sessionErr: nil, - registry: func() Registry { - reg := NewMockRegistry(gomock.NewController(t)) + registry: func() registry.Registry { + reg := registrymock.NewMockRegistry(gomock.NewController(t)) reg.EXPECT().DocumentSymbols(uri.URI("file:///test.go")).Return([]*model.SymbolOccurrence{ { Info: &model.SymbolInformation{ @@ -2257,7 +2259,7 @@ func TestControllerGetDocumentSymbols(t *testing.T) { c := &controller{ sessions: sessionRepository, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ "/some/path": tt.registry, }, logger: zap.NewNop().Sugar(), @@ -2281,7 +2283,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { name string descriptors []model.Descriptor overrideWSR string - setupMocks func(*gomock.Controller) (controller, *MockRegistry) + setupMocks func(*gomock.Controller) (controller, *registrymock.MockRegistry) expected *model.SymbolOccurrence expectedErr error }{ @@ -2298,7 +2300,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { }, }, overrideWSR: "", - setupMocks: func(ctrl *gomock.Controller) (controller, *MockRegistry) { + setupMocks: func(ctrl *gomock.Controller) (controller, *registrymock.MockRegistry) { sessionRepo := repositorymock.NewMockRepository(ctrl) sessionRepo.EXPECT().GetFromContext(gomock.Any()).Return(nil, errors.New("no session")).AnyTimes() return controller{ @@ -2312,7 +2314,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { { name: "no registry", descriptors: []model.Descriptor{}, - setupMocks: func(ctrl *gomock.Controller) (controller, *MockRegistry) { + setupMocks: func(ctrl *gomock.Controller) (controller, *registrymock.MockRegistry) { sessionRepo := repositorymock.NewMockRepository(ctrl) s := &entity.Session{ UUID: factory.UUID(), @@ -2322,7 +2324,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { return controller{ sessions: sessionRepo, logger: zap.NewNop().Sugar(), - registries: map[string]Registry{}, + registries: map[string]registry.Registry{}, }, nil }, expected: nil, @@ -2340,7 +2342,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { Suffix: scip.Descriptor_Type, }, }, - setupMocks: func(ctrl *gomock.Controller) (controller, *MockRegistry) { + setupMocks: func(ctrl *gomock.Controller) (controller, *registrymock.MockRegistry) { sessionRepo := repositorymock.NewMockRepository(ctrl) s := &entity.Session{ UUID: factory.UUID(), @@ -2348,7 +2350,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { s.WorkspaceRoot = "/some/path" sessionRepo.EXPECT().GetFromContext(gomock.Any()).Return(s, nil).AnyTimes() - reg := NewMockRegistry(ctrl) + reg := registrymock.NewMockRegistry(ctrl) reg.EXPECT().GetSymbolDefinitionOccurrence([]model.Descriptor{ { Name: "test", @@ -2371,7 +2373,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { return controller{ sessions: sessionRepo, logger: zap.NewNop().Sugar(), - registries: map[string]Registry{ + registries: map[string]registry.Registry{ "/some/path": reg, }, }, reg @@ -2399,7 +2401,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { Suffix: scip.Descriptor_Type, }, }, - setupMocks: func(ctrl *gomock.Controller) (controller, *MockRegistry) { + setupMocks: func(ctrl *gomock.Controller) (controller, *registrymock.MockRegistry) { sessionRepo := repositorymock.NewMockRepository(ctrl) s := &entity.Session{ UUID: factory.UUID(), @@ -2407,7 +2409,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { s.WorkspaceRoot = "/some/path" sessionRepo.EXPECT().GetFromContext(gomock.Any()).Return(s, nil).AnyTimes() - reg := NewMockRegistry(ctrl) + reg := registrymock.NewMockRegistry(ctrl) reg.EXPECT().GetSymbolDefinitionOccurrence([]model.Descriptor{ { Name: "test", @@ -2422,7 +2424,7 @@ func TestControllerGetSymbolDefinitionOccurrence(t *testing.T) { return controller{ sessions: sessionRepo, logger: zap.NewNop().Sugar(), - registries: map[string]Registry{ + registries: map[string]registry.Registry{ "/some/path": reg, }, }, reg @@ -2677,13 +2679,13 @@ func TestGetLatestPosition(t *testing.T) { func TestController_DidOpen(t *testing.T) { tests := []struct { name string - setupMocks func(mockSesh *repositorymock.MockRepository, mockReg *MockRegistry) (*entity.Session, error) + setupMocks func(mockSesh *repositorymock.MockRepository, mockReg *registrymock.MockRegistry) (*entity.Session, error) params *protocol.DidOpenTextDocumentParams expectedError string }{ { name: "successful did open", - setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *MockRegistry) (*entity.Session, error) { + setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *registrymock.MockRegistry) (*entity.Session, error) { sesh := &entity.Session{ WorkspaceRoot: "/test/workspace", } @@ -2700,7 +2702,7 @@ func TestController_DidOpen(t *testing.T) { }, { name: "session error", - setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *MockRegistry) (*entity.Session, error) { + setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *registrymock.MockRegistry) (*entity.Session, error) { mockSesh.EXPECT().GetFromContext(gomock.Any()).Return(nil, assert.AnError) return nil, assert.AnError }, @@ -2714,7 +2716,7 @@ func TestController_DidOpen(t *testing.T) { }, { name: "no registry for workspace", - setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *MockRegistry) (*entity.Session, error) { + setupMocks: func(mockSesh *repositorymock.MockRepository, mockReg *registrymock.MockRegistry) (*entity.Session, error) { sesh := &entity.Session{ WorkspaceRoot: "/different/workspace", } @@ -2734,13 +2736,13 @@ func TestController_DidOpen(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) mockSesh := repositorymock.NewMockRepository(ctrl) - mockReg := NewMockRegistry(ctrl) + mockReg := registrymock.NewMockRegistry(ctrl) _, _ = tt.setupMocks(mockSesh, mockReg) c := &controller{ sessions: mockSesh, - registries: map[string]Registry{ + registries: map[string]registry.Registry{ "/test/workspace": mockReg, }, } From b8d71c77f84c3f4c6d22f45c7e23160d712d1d5e Mon Sep 17 00:00:00 2001 From: zerunz Date: Tue, 4 Nov 2025 00:27:53 +0000 Subject: [PATCH 2/5] format --- src/ulsp/controller/scip/scip.go | 2 +- src/ulsp/controller/scip/scip_test.go | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ulsp/controller/scip/scip.go b/src/ulsp/controller/scip/scip.go index bd0c7c4..9843155 100644 --- a/src/ulsp/controller/scip/scip.go +++ b/src/ulsp/controller/scip/scip.go @@ -12,13 +12,13 @@ import ( tally "github.com/uber-go/tally/v4" "github.com/uber/scip-lsp/src/scip-lib/mapper" "github.com/uber/scip-lsp/src/scip-lib/model" + "github.com/uber/scip-lsp/src/scip-lib/registry" diagnostics "github.com/uber/scip-lsp/src/ulsp/controller/diagnostics" docsync "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync" "github.com/uber/scip-lsp/src/ulsp/entity" ulspplugin "github.com/uber/scip-lsp/src/ulsp/entity/ulsp-plugin" ideclient "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client" "github.com/uber/scip-lsp/src/ulsp/internal/fs" - "github.com/uber/scip-lsp/src/scip-lib/registry" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" ulsp_mapper "github.com/uber/scip-lsp/src/ulsp/mapper" "github.com/uber/scip-lsp/src/ulsp/repository/session" diff --git a/src/ulsp/controller/scip/scip_test.go b/src/ulsp/controller/scip/scip_test.go index 036d5f1..91f77f6 100644 --- a/src/ulsp/controller/scip/scip_test.go +++ b/src/ulsp/controller/scip/scip_test.go @@ -18,13 +18,13 @@ import ( tally "github.com/uber-go/tally/v4" "github.com/uber/scip-lsp/src/scip-lib/mapper" "github.com/uber/scip-lsp/src/scip-lib/model" + "github.com/uber/scip-lsp/src/scip-lib/registry" + "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock" "github.com/uber/scip-lsp/src/ulsp/controller/diagnostics/diagnosticsmock" docsync "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync" "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync/docsyncmock" "github.com/uber/scip-lsp/src/ulsp/entity" "github.com/uber/scip-lsp/src/ulsp/factory" - "github.com/uber/scip-lsp/src/scip-lib/registry" - "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock" "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client/ideclientmock" "github.com/uber/scip-lsp/src/ulsp/internal/fs/fsmock" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" From 62a1d07923e680ce7ed138dc3015ae0fac3ed0f2 Mon Sep 17 00:00:00 2001 From: zerunz Date: Mon, 3 Nov 2025 23:54:17 +0000 Subject: [PATCH 3/5] chore(scip-registry) Replace ulsp/controller/scip partialScipRegistry with the scip-lib/registry one --- src/ulsp/controller/scip/scip.go | 1 + src/ulsp/controller/scip/scip_test.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/ulsp/controller/scip/scip.go b/src/ulsp/controller/scip/scip.go index 9843155..776e967 100644 --- a/src/ulsp/controller/scip/scip.go +++ b/src/ulsp/controller/scip/scip.go @@ -19,6 +19,7 @@ import ( ulspplugin "github.com/uber/scip-lsp/src/ulsp/entity/ulsp-plugin" ideclient "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client" "github.com/uber/scip-lsp/src/ulsp/internal/fs" + "github.com/uber/scip-lsp/src/scip-lib/registry" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" ulsp_mapper "github.com/uber/scip-lsp/src/ulsp/mapper" "github.com/uber/scip-lsp/src/ulsp/repository/session" diff --git a/src/ulsp/controller/scip/scip_test.go b/src/ulsp/controller/scip/scip_test.go index 91f77f6..f5608d1 100644 --- a/src/ulsp/controller/scip/scip_test.go +++ b/src/ulsp/controller/scip/scip_test.go @@ -25,6 +25,8 @@ import ( "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync/docsyncmock" "github.com/uber/scip-lsp/src/ulsp/entity" "github.com/uber/scip-lsp/src/ulsp/factory" + "github.com/uber/scip-lsp/src/scip-lib/registry" + "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock" "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client/ideclientmock" "github.com/uber/scip-lsp/src/ulsp/internal/fs/fsmock" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" From 659bce7be8fdeafb04f18eec330f50547d359c0a Mon Sep 17 00:00:00 2001 From: zerunz Date: Tue, 4 Nov 2025 00:27:53 +0000 Subject: [PATCH 4/5] format --- src/ulsp/controller/scip/scip.go | 1 - src/ulsp/controller/scip/scip_test.go | 2 -- 2 files changed, 3 deletions(-) diff --git a/src/ulsp/controller/scip/scip.go b/src/ulsp/controller/scip/scip.go index 776e967..9843155 100644 --- a/src/ulsp/controller/scip/scip.go +++ b/src/ulsp/controller/scip/scip.go @@ -19,7 +19,6 @@ import ( ulspplugin "github.com/uber/scip-lsp/src/ulsp/entity/ulsp-plugin" ideclient "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client" "github.com/uber/scip-lsp/src/ulsp/internal/fs" - "github.com/uber/scip-lsp/src/scip-lib/registry" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" ulsp_mapper "github.com/uber/scip-lsp/src/ulsp/mapper" "github.com/uber/scip-lsp/src/ulsp/repository/session" diff --git a/src/ulsp/controller/scip/scip_test.go b/src/ulsp/controller/scip/scip_test.go index f5608d1..91f77f6 100644 --- a/src/ulsp/controller/scip/scip_test.go +++ b/src/ulsp/controller/scip/scip_test.go @@ -25,8 +25,6 @@ import ( "github.com/uber/scip-lsp/src/ulsp/controller/doc-sync/docsyncmock" "github.com/uber/scip-lsp/src/ulsp/entity" "github.com/uber/scip-lsp/src/ulsp/factory" - "github.com/uber/scip-lsp/src/scip-lib/registry" - "github.com/uber/scip-lsp/src/scip-lib/registry/registrymock" "github.com/uber/scip-lsp/src/ulsp/gateway/ide-client/ideclientmock" "github.com/uber/scip-lsp/src/ulsp/internal/fs/fsmock" notifier "github.com/uber/scip-lsp/src/ulsp/internal/persistent-notifier" From 1a9dc932ece6b053073d194c52bfeb0c879c2d8c Mon Sep 17 00:00:00 2001 From: zerunz Date: Fri, 14 Nov 2025 22:44:30 +0000 Subject: [PATCH 5/5] chore(scip): remove package-registry in ulsp/controller/scip --- src/ulsp/controller/scip/BUILD.bazel | 5 - src/ulsp/controller/scip/partial_registry.go | 392 ----- .../controller/scip/partial_registry_test.go | 1515 ----------------- src/ulsp/controller/scip/scip.go | 2 +- 4 files changed, 1 insertion(+), 1913 deletions(-) delete mode 100644 src/ulsp/controller/scip/partial_registry.go delete mode 100644 src/ulsp/controller/scip/partial_registry_test.go diff --git a/src/ulsp/controller/scip/BUILD.bazel b/src/ulsp/controller/scip/BUILD.bazel index dd87cb4..ff4263e 100644 --- a/src/ulsp/controller/scip/BUILD.bazel +++ b/src/ulsp/controller/scip/BUILD.bazel @@ -5,7 +5,6 @@ go_library( name = "go_default_library", srcs = [ "consume.go", - "partial_registry.go", "scip.go", "scip_notify.go", "types.go", @@ -15,7 +14,6 @@ go_library( deps = [ "//src/scip-lib/mapper:go_default_library", "//src/scip-lib/model:go_default_library", - "//src/scip-lib/partialloader:go_default_library", "//src/scip-lib/registry:go_default_library", "//src/ulsp/controller/diagnostics:go_default_library", "//src/ulsp/controller/doc-sync:go_default_library", @@ -48,7 +46,6 @@ go_test( name = "go_default_test", srcs = [ "consume_test.go", - "partial_registry_test.go", "scip_notify_test.go", "scip_test.go", "types_test.go", @@ -59,7 +56,6 @@ go_test( deps = [ "//src/scip-lib/mapper:go_default_library", "//src/scip-lib/model:go_default_library", - "//src/scip-lib/partialloader:go_loader_gomock_library", "//src/scip-lib/registry:go_default_library", "//src/scip-lib/registry:go_registry_gomock_library", "//src/ulsp/controller/diagnostics:go_diagnostics_gomock_library", @@ -82,7 +78,6 @@ go_test( "@org_uber_go_config//:go_default_library", "@org_uber_go_mock//gomock:go_default_library", "@org_uber_go_zap//:go_default_library", - "@org_uber_go_zap//zaptest:go_default_library", "@rules_go//go/tools/bazel:go_default_library", ], ) diff --git a/src/ulsp/controller/scip/partial_registry.go b/src/ulsp/controller/scip/partial_registry.go deleted file mode 100644 index a4632ba..0000000 --- a/src/ulsp/controller/scip/partial_registry.go +++ /dev/null @@ -1,392 +0,0 @@ -package scip - -import ( - "errors" - "io" - "path" - "path/filepath" - "runtime" - "strings" - - "github.com/sourcegraph/scip/bindings/go/scip" - "github.com/uber/scip-lsp/src/scip-lib/mapper" - "github.com/uber/scip-lsp/src/scip-lib/model" - "github.com/uber/scip-lsp/src/scip-lib/partialloader" - "go.lsp.dev/protocol" - "go.lsp.dev/uri" - "go.uber.org/zap" -) - -type partialScipRegistry struct { - WorkspaceRoot string - Index partialloader.PartialIndex - IndexFolder string - logger *zap.SugaredLogger -} - -// Legacy methods - -// GetURI gets the full path to a document as an LSP uri. -func (p *partialScipRegistry) GetURI(relPath string) uri.URI { - return uri.File(path.Join(p.WorkspaceRoot, relPath)) -} - -// GetDocumentSymbolForFile implements Registry. -func (p *partialScipRegistry) GetDocumentSymbolForFile(uri uri.URI) (*[]*SymbolData, error) { - return nil, errors.New("not implemented") -} - -// GetFileInfo implements Registry. -func (p *partialScipRegistry) GetFileInfo(uri uri.URI) *FileInfo { - return nil -} - -// GetPackageInfo implements Registry. -func (p *partialScipRegistry) GetPackageInfo(pkgID PackageID) *PackageMeta { - return nil -} - -// GetSymbolForPosition implements Registry. -func (p *partialScipRegistry) GetSymbolForPosition(uri uri.URI, loc protocol.Position) (*model.Occurrence, *SymbolData, error) { - return nil, nil, errors.New("not implemented") -} - -// vNext Methods -// LoadIndex implements Registry. -func (p *partialScipRegistry) LoadIndex(indexReader io.ReadSeeker) error { - if indexReader == nil { - return errors.New("index reader is nil") - } - return p.Index.LoadIndex("", indexReader) -} - -// LoadIndexFile implements Registry. -func (p *partialScipRegistry) LoadIndexFile(indexPath string) error { - return p.Index.LoadIndexFile(indexPath) -} - -// SetDocumentLoadedCallback implements Registry. -func (p *partialScipRegistry) SetDocumentLoadedCallback(callback func(*model.Document)) { - p.Index.SetDocumentLoadedCallback(callback) -} - -// DidOpen implements Registry. -func (p *partialScipRegistry) DidOpen(uri uri.URI, text string) error { - relativePath := p.uriToRelativePath(uri) - - doc, err := p.Index.LoadDocument(relativePath) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", relativePath, err) - return err - } - - if doc == nil { - p.logger.Infof("document not found: %s", relativePath) - return nil - } - - return nil -} - -// DidClose implements Registry. -func (p *partialScipRegistry) DidClose(sourceURI uri.URI) error { - return nil -} - -// TODO(IDE-1640): Add support for the registry to store and retrieve multiple versions of the same symbol from different jars that may reference different source documents. -func (p *partialScipRegistry) GetSymbolDefinitionOccurrence(descriptors []model.Descriptor, version string) (*model.SymbolOccurrence, error) { - symbolInformation, defDocPath, err := p.Index.GetSymbolInformationFromDescriptors(descriptors, version) - if err != nil { - return nil, err - } - - if symbolInformation == nil { - return nil, nil - } - - result := &model.SymbolOccurrence{ - Info: symbolInformation, - Location: uri.File(filepath.Join(p.WorkspaceRoot, defDocPath)), - } - - defDoc, err := p.Index.LoadDocument(defDocPath) - if err != nil { - return nil, err - } else if defDoc == nil { - return nil, nil - } - - definitionOccs := GetOccurrencesForSymbol(defDoc.Occurrences, symbolInformation.Symbol, scip.SymbolRole_Definition) - if len(definitionOccs) > 0 { - result.Occurrence = definitionOccs[0] - } - - return result, nil -} - -// Definition implements Registry. -func (p *partialScipRegistry) Definition(sourceURI uri.URI, pos protocol.Position) (sourceSymOcc *model.SymbolOccurrence, defSymOcc *model.SymbolOccurrence, err error) { - doc, err := p.Index.LoadDocument(p.uriToRelativePath(sourceURI)) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", p.uriToRelativePath(sourceURI), err) - return nil, nil, err - } - - if doc == nil { - return nil, nil, nil - } - - var sourceOccurrence *model.Occurrence - var definitionOcc *model.Occurrence - var symbolInformation *model.SymbolInformation - var defDocURI uri.URI - - sourceOccurrence = GetOccurrenceForPosition(doc.Occurrences, pos) - if sourceOccurrence == nil { - return nil, nil, nil - } - - if scip.IsLocalSymbol(sourceOccurrence.Symbol) { - // Local symbols are file unique, so we can just return the first definition occurrence - definitionOccs := GetOccurrencesForSymbol(doc.Occurrences, sourceOccurrence.Symbol, scip.SymbolRole_Definition) - if len(definitionOccs) > 0 { - definitionOcc = definitionOccs[0] - defDocURI = sourceURI - } - // A local symbol may not have SymbolInformation - symbolInformation = GetLocalSymbolInformation(doc.Symbols, sourceOccurrence.Symbol) - - } else { - // Descriptor-based lookup in the prefix tree for global symbols. - symbol, err := model.ParseScipSymbol(sourceOccurrence.Symbol) - if err != nil { - p.logger.Errorf("failed to parse symbol %s: %s", sourceOccurrence.Symbol, err) - return nil, nil, err - } - - def, err := p.GetSymbolDefinitionOccurrence(mapper.ScipDescriptorsToModelDescriptors(symbol.Descriptors), symbol.Package.Version) - if err != nil { - p.logger.Errorf("failed to get symbol definition occurrence for %s: %s", sourceOccurrence.Symbol, err) - return nil, nil, err - } else if def == nil { - p.logger.Errorf("failed to get symbol definition occurrence for %s: %s", sourceOccurrence.Symbol, err) - return nil, nil, nil - } - - definitionOcc = def.Occurrence - defDocURI = def.Location - symbolInformation = def.Info - } - - sourceSymOcc = &model.SymbolOccurrence{ - Info: symbolInformation, - Occurrence: sourceOccurrence, - Location: sourceURI, - } - - defSymOcc = &model.SymbolOccurrence{ - Info: symbolInformation, - Occurrence: definitionOcc, - Location: defDocURI, - } - - return sourceSymOcc, defSymOcc, nil -} - -// References implements Registry. -func (p *partialScipRegistry) References(sourceURI uri.URI, pos protocol.Position) ([]protocol.Location, error) { - doc, err := p.Index.LoadDocument(p.uriToRelativePath(sourceURI)) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", sourceURI, err) - return nil, err - } - if doc == nil { - return nil, nil - } - - sourceOccurrence := GetOccurrenceForPosition(doc.Occurrences, pos) - if sourceOccurrence == nil { - return nil, nil - } - - // Get all references to this symbol across all documents - locations := make([]protocol.Location, 0) - - // For local symbols, only search in current document - if scip.IsLocalSymbol(sourceOccurrence.Symbol) { - for _, occ := range doc.Occurrences { - if occ.Symbol == sourceOccurrence.Symbol { - locations = append(locations, *mapper.ScipOccurrenceToLocation(sourceURI, occ)) - } - } - return locations, nil - } - - // For global symbols, search all documents - occurrences, err := p.Index.References(sourceOccurrence.Symbol) - if err != nil { - p.logger.Errorf("failed to get references for %s: %s", sourceOccurrence.Symbol, err) - return nil, err - } - - for relDocPath, occs := range occurrences { - for _, occ := range occs { - locations = append(locations, *mapper.ScipOccurrenceToLocation(uri.File(filepath.Join(p.WorkspaceRoot, relDocPath)), occ)) - } - } - - return locations, nil -} - -// Hover implements Registry. -func (p *partialScipRegistry) Hover(uri uri.URI, pos protocol.Position) (string, *model.Occurrence, error) { - doc, err := p.Index.LoadDocument(p.uriToRelativePath(uri)) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", uri, err) - return "", nil, err - } - if doc == nil { - return "", nil, nil - } - - occurrence := GetOccurrenceForPosition(doc.Occurrences, pos) - if occurrence == nil { - return "", nil, nil - } - var docs string - - symbolInformation, _, err := p.Index.GetSymbolInformation(occurrence.Symbol) - if err != nil { - p.logger.Errorf("failed to get symbol information for %s: %s", occurrence.Symbol, err) - return "", nil, err - } - - if len(occurrence.OverrideDocumentation) > 0 { - docs += strings.Join(occurrence.OverrideDocumentation, "\n") - } else if symbolInformation != nil && len(symbolInformation.Documentation) > 0 { - docs += strings.Join(symbolInformation.Documentation, "\n") - } else if symbolInformation != nil && symbolInformation.SignatureDocumentation != nil { - docs += symbolInformation.SignatureDocumentation.Text - } - - return docs, occurrence, nil -} - -// DocumentSymbols implements Registry. -func (p *partialScipRegistry) DocumentSymbols(uri uri.URI) ([]*model.SymbolOccurrence, error) { - doc, err := p.Index.LoadDocument(p.uriToRelativePath(uri)) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", uri, err) - return nil, err - } - - if doc == nil { - return nil, nil - } - - symbolOccurrences := make([]*model.SymbolOccurrence, 0) - for _, occ := range doc.Occurrences { - if scip.IsGlobalSymbol(occ.Symbol) && occ.SymbolRoles&int32(scip.SymbolRole_Definition) > 0 { - info := doc.SymbolMap[occ.Symbol] - if info != nil { - if info.DisplayName == "" { - info.DisplayName = model.ParseScipSymbolToDisplayName(info.Symbol) - } - symbolOccurrences = append(symbolOccurrences, &model.SymbolOccurrence{ - Info: info, - Occurrence: occ, - Location: uri, - }) - } - } - } - - return symbolOccurrences, nil -} - -// Diagnostics implements Registry. -func (p *partialScipRegistry) Diagnostics(uri uri.URI) ([]*model.Diagnostic, error) { - return nil, errors.New("not implemented") -} - -// GetSymbolDataForSymbol implements Registry. -func (p *partialScipRegistry) GetSymbolDataForSymbol(symbol string, localPkg *PackageMeta) (*SymbolData, error) { - return nil, errors.New("not implemented") -} - -// GetSymbolOccurrence implements Registry. -func (p *partialScipRegistry) GetSymbolOccurrence(uri uri.URI, pos protocol.Position) (*model.SymbolOccurrence, error) { - return nil, errors.New("not implemented") -} - -// Implementation implements Registry. -func (p *partialScipRegistry) Implementation(sourceURI uri.URI, pos protocol.Position) ([]protocol.Location, error) { - doc, err := p.Index.LoadDocument(p.uriToRelativePath(sourceURI)) - if err != nil { - p.logger.Errorf("failed to load document %s: %s", sourceURI, err) - return nil, err - } - if doc == nil { - return nil, nil - } - - sourceOccurrence := GetOccurrenceForPosition(doc.Occurrences, pos) - if sourceOccurrence == nil { - return nil, nil - } - - // Local symbols typically don't have implementation relationships - if scip.IsLocalSymbol(sourceOccurrence.Symbol) { - return []protocol.Location{}, nil - } - - locations := make([]protocol.Location, 0) - - implementors, err := p.Index.Implementations(sourceOccurrence.Symbol) - if err != nil { - p.logger.Errorf("failed to get implementing symbols for %s: %s", sourceOccurrence.Symbol, err) - return nil, err - } - for _, implSym := range implementors { - implementingSymbol, err := model.ParseScipSymbol(implSym) - if err != nil { - p.logger.Errorf("failed to parse implementing symbol %s: %s", implSym, err) - continue - } - implOcc, err := p.GetSymbolDefinitionOccurrence( - mapper.ScipDescriptorsToModelDescriptors(implementingSymbol.Descriptors), - implementingSymbol.Package.Version, - ) - if err != nil { - p.logger.Errorf("failed to get definition for implementing symbol %s: %s", implSym, err) - continue - } - if implOcc != nil && implOcc.Occurrence != nil { - locations = append(locations, *mapper.ScipOccurrenceToLocation(implOcc.Location, implOcc.Occurrence)) - } - } - - return locations, nil -} - -func (p *partialScipRegistry) uriToRelativePath(uri uri.URI) string { - rel, err := filepath.Rel(p.WorkspaceRoot, uri.Filename()) - if err != nil { - return "" - } - return rel -} - -func (p *partialScipRegistry) LoadConcurrency() int { - return runtime.NumCPU() / 2 -} - -// NewPartialScipRegistry creates a new partial SCIP registry -func NewPartialScipRegistry(workspaceRoot string, indexFolder string, logger *zap.SugaredLogger) Registry { - return &partialScipRegistry{ - WorkspaceRoot: workspaceRoot, - IndexFolder: indexFolder, - Index: partialloader.NewPartialLoadedIndex(indexFolder), - logger: logger, - } -} diff --git a/src/ulsp/controller/scip/partial_registry_test.go b/src/ulsp/controller/scip/partial_registry_test.go deleted file mode 100644 index b8e0290..0000000 --- a/src/ulsp/controller/scip/partial_registry_test.go +++ /dev/null @@ -1,1515 +0,0 @@ -package scip - -import ( - "io" - "strings" - "testing" - - scipproto "github.com/sourcegraph/scip/bindings/go/scip" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - "github.com/uber/scip-lsp/src/scip-lib/model" - partialloadermock "github.com/uber/scip-lsp/src/scip-lib/partialloader/partial_loader_mock" - "go.lsp.dev/protocol" - "go.lsp.dev/uri" - "go.uber.org/mock/gomock" - "go.uber.org/zap" - "go.uber.org/zap/zaptest" -) - -func TestPartialScipRegistry_UnimplementedMethods(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - registry := &partialScipRegistry{ - WorkspaceRoot: "/test/workspace", - Index: mockIndex, - } - - t.Run("GetUri returns URI", func(t *testing.T) { - u := registry.GetURI("test/file.go") - assert.True(t, strings.HasSuffix(string(u), "test/file.go")) - }) - - t.Run("GetDocumentSymbolForFile returns error", func(t *testing.T) { - _, err := registry.GetDocumentSymbolForFile(uri.URI("file:///test/file.go")) - assert.Error(t, err) - }) - - t.Run("GetFileInfo returns error", func(t *testing.T) { - info := registry.GetFileInfo(uri.URI("file:///test/file.go")) - assert.Nil(t, info) - }) - - t.Run("GetPackageInfo returns error", func(t *testing.T) { - pkg := registry.GetPackageInfo("test-package") - assert.Nil(t, pkg) - }) - - t.Run("GetSymbolForPosition returns error", func(t *testing.T) { - _, _, err := registry.GetSymbolForPosition(uri.URI("file:///test/file.go"), protocol.Position{Line: 1, Character: 1}) - assert.Error(t, err) - }) - - t.Run("Diagnostics returns error", func(t *testing.T) { - _, err := registry.Diagnostics(uri.URI("file:///test/file.go")) - assert.Error(t, err) - assert.Equal(t, "not implemented", err.Error()) - }) - - t.Run("GetSymbolDataForSymbol returns error", func(t *testing.T) { - _, err := registry.GetSymbolDataForSymbol("test-symbol", nil) - assert.Error(t, err) - assert.Equal(t, "not implemented", err.Error()) - }) - - t.Run("GetSymbolOccurrence returns error", func(t *testing.T) { - _, err := registry.GetSymbolOccurrence(uri.URI("file:///test/file.go"), protocol.Position{Line: 1, Character: 1}) - assert.Error(t, err) - assert.Equal(t, "not implemented", err.Error()) - }) - - t.Run("LoadIndex returns error", func(t *testing.T) { - err := registry.LoadIndex(nil) - assert.Error(t, err) - }) - - t.Run("LoadConcurrency returns proper value", func(t *testing.T) { - concurrency := registry.LoadConcurrency() - assert.NotZero(t, concurrency) - }) -} - -// MockReadSeeker is a manual mock for testing the ReadSeeker interface -type MockReadSeeker struct { - io.Reader - io.Seeker -} - -func TestPartialScipRegistry_LoadIndex(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - mockIndex.EXPECT().LoadIndex(gomock.Any(), gomock.Any()).Return(nil) - - registry := &partialScipRegistry{ - WorkspaceRoot: "/test/workspace", - Index: mockIndex, - } - - // Create a simple mock reader (implementation details aren't important for this test) - mockReader := &MockReadSeeker{} - - // Test that LoadIndex delegates to the Index - err := registry.LoadIndex(mockReader) - - // Verify the method was called and returned the expected result - require.NoError(t, err) -} - -func TestNewPartialScipRegistry(t *testing.T) { - registry := NewPartialScipRegistry("/test/workspace", "/test/index", zap.NewNop().Sugar()) - - // Type assertion to check the returned interface is of the correct implementation type - partialRegistry, ok := registry.(*partialScipRegistry) - require.True(t, ok, "Expected registry to be of type *partialScipRegistry") - - assert.Equal(t, "/test/workspace", partialRegistry.WorkspaceRoot) - assert.NotNil(t, partialRegistry.Index, "Expected Index to be initialized") -} - -func TestPartialScipRegistry_DidOpen(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - uri uri.URI - text string - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedError string - }{ - { - name: "successful document load", - uri: uri.File("/workspace/test.go"), - text: "package main", - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{}, nil) - }, - }, - { - name: "document not found", - uri: uri.File("/workspace/missing.go"), - text: "package main", - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("missing.go"). - Return(nil, nil) - }, - }, - { - name: "error loading document", - uri: uri.File("/workspace/error.go"), - text: "package main", - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("error.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - err := registry.DidOpen(tt.uri, tt.text) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - } else { - require.NoError(t, err) - } - }) - } -} - -func TestPartialScipRegistry_UriToRelativePath(t *testing.T) { - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - workspaceRoot string - uri uri.URI - expected string - }{ - { - name: "valid relative path", - workspaceRoot: "/workspace", - uri: uri.File("/workspace/src/test.go"), - expected: "src/test.go", - }, - { - name: "uri outside workspace", - workspaceRoot: "/workspace", - uri: uri.File("/other/test.go"), - expected: "../other/test.go", - }, - { - name: "same directory", - workspaceRoot: "/workspace", - uri: uri.File("/workspace/test.go"), - expected: "test.go", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: tt.workspaceRoot, - logger: logger, - } - - result := registry.uriToRelativePath(tt.uri) - assert.Equal(t, tt.expected, result) - }) - } -} - -func TestPartialScipRegistry_LoadIndexFile(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - indexPath string - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedError string - }{ - { - name: "successful index load", - indexPath: "/test/index.scip", - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadIndexFile("/test/index.scip"). - Return(nil) - }, - }, - { - name: "error loading index", - indexPath: "/test/error.scip", - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadIndexFile("/test/error.scip"). - Return(assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - err := registry.LoadIndexFile(tt.indexPath) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - } else { - require.NoError(t, err) - } - }) - } -} - -func TestPartialScipRegistry_SetDocumentLoadedCallback(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - // Create a test callback function - testCallback := func(*model.Document) {} - - // Expect the callback to be set on the mock index - mockIndex.EXPECT().SetDocumentLoadedCallback(gomock.Any()) - - // Call the method - registry.SetDocumentLoadedCallback(testCallback) -} - -func TestPartialScipRegistry_GetSymbolDefinitionOccurrence(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - descriptors []model.Descriptor - expectedResult *model.SymbolOccurrence - setupMock func(mock *partialloadermock.MockPartialIndex) - wantError bool - }{ - { - name: "empty descriptors", - descriptors: []model.Descriptor{}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{}, gomock.Any()). - Return(nil, "", nil) - }, - expectedResult: nil, - wantError: false, - }, - { - name: "symbol information error", - descriptors: []model.Descriptor{}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{}, gomock.Any()). - Return(nil, "", assert.AnError) - }, - expectedResult: nil, - wantError: true, - }, - { - name: "valid match with occurrence", - descriptors: []model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "Test", - Suffix: scipproto.Descriptor_Type, - }, - }, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "Test", - Suffix: scipproto.Descriptor_Type, - }, - }, gomock.Any()). - Return(&model.SymbolInformation{ - Symbol: "test", - }, "path/to/doc.java", nil) - mock.EXPECT(). - LoadDocument("path/to/doc.java"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{ - { - Symbol: "other symbol", - Range: []int32{10, 3, 5}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - { - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - { - Symbol: "test", - Range: []int32{13, 3, 5}, - SymbolRoles: int32(scipproto.SymbolRole_ReadAccess), - }, - }, - }, nil) - }, - expectedResult: &model.SymbolOccurrence{ - Location: "file:///workspace/root/path/to/doc.java", - Info: &model.SymbolInformation{ - Symbol: "test", - }, - Occurrence: &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - }, - wantError: false, - }, - { - name: "valid match with missing occurrence", - descriptors: []model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "test", - Suffix: scipproto.Descriptor_Type, - }, - }, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "test", - Suffix: scipproto.Descriptor_Type, - }, - }, gomock.Any()). - Return(&model.SymbolInformation{ - Symbol: "test", - }, "path/to/doc.java", nil) - mock.EXPECT(). - LoadDocument("path/to/doc.java"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{ - { - Symbol: "other symbol", - Range: []int32{10, 3, 5}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - { - Symbol: "test", - Range: []int32{13, 3, 5}, - SymbolRoles: int32(scipproto.SymbolRole_ReadAccess), - }, - }, - }, nil) - }, - expectedResult: &model.SymbolOccurrence{ - Location: "file:///workspace/root/path/to/doc.java", - Info: &model.SymbolInformation{ - Symbol: "test", - }, - Occurrence: nil, - }, - wantError: false, - }, - { - name: "load document error", - descriptors: []model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "test", - Suffix: scipproto.Descriptor_Type, - }, - }, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "sample", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "test", - Suffix: scipproto.Descriptor_Type, - }, - }, gomock.Any()). - Return(&model.SymbolInformation{ - Symbol: "test", - }, "/path/to/doc.java", nil) - mock.EXPECT(). - LoadDocument("/path/to/doc.java"). - Return(nil, assert.AnError) - }, - expectedResult: nil, - wantError: true, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace/root", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - result, err := registry.GetSymbolDefinitionOccurrence(tt.descriptors, ".") - - if tt.wantError { - require.Error(t, err) - } else { - require.NoError(t, err) - assert.Equal(t, tt.expectedResult, result) - } - }) - } -} - -func TestPartialScipRegistry_Definition(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - sourceURI uri.URI - pos protocol.Position - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedSource *model.SymbolOccurrence - expectedDef *model.SymbolOccurrence - expectedError string - }{ - { - name: "document load error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "document not found", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, nil) - }, - }, - { - name: "no occurrence at position", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{}, - }, nil) - }, - }, - { - name: "local symbol with definition", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: "local 1", - Range: []int32{1, 1, 1, 2}, // start_line, start_char, end_line, end_char - } - defOcc := &model.Occurrence{ - Symbol: "local 1", - Range: []int32{0, 0, 0, 1}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - } - symInfo := &model.SymbolInformation{ - Symbol: "local 1", - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc, defOcc}, - Symbols: []*model.SymbolInformation{symInfo}, - }, nil) - }, - expectedSource: &model.SymbolOccurrence{ - Info: &model.SymbolInformation{Symbol: "local 1"}, - Occurrence: &model.Occurrence{ - Symbol: "local 1", - Range: []int32{1, 1, 1, 2}, - }, - Location: uri.File("/workspace/test.go"), - }, - expectedDef: &model.SymbolOccurrence{ - Info: &model.SymbolInformation{Symbol: "local 1"}, - Occurrence: &model.Occurrence{ - Symbol: "local 1", - Range: []int32{0, 0, 0, 1}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - Location: uri.File("/workspace/test.go"), - }, - }, - { - name: "global symbol with definition", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - defOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{0, 0, 0, 1}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - } - symInfo := &model.SymbolInformation{ - Symbol: tracingUUIDKey, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "code.uber.internal/devexp/test_management/tracing", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "PipelineUUIDTagKey", - Suffix: scipproto.Descriptor_Term, - }, - }, gomock.Any()). - Return(symInfo, "def.go", nil) - mock.EXPECT(). - LoadDocument("def.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{defOcc}, - }, nil) - }, - expectedSource: &model.SymbolOccurrence{ - Info: &model.SymbolInformation{Symbol: tracingUUIDKey}, - Occurrence: &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - }, - Location: uri.File("/workspace/test.go"), - }, - expectedDef: &model.SymbolOccurrence{ - Info: &model.SymbolInformation{Symbol: tracingUUIDKey}, - Occurrence: &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{0, 0, 0, 1}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - Location: uri.File("/workspace/def.go"), - }, - }, - { - name: "global symbol info not found", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "code.uber.internal/devexp/test_management/tracing", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "PipelineUUIDTagKey", - Suffix: scipproto.Descriptor_Term, - }, - }, gomock.Any()). - Return(nil, "def.go", nil) - }, - }, - { - name: "error getting symbol information", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "code.uber.internal/devexp/test_management/tracing", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "PipelineUUIDTagKey", - Suffix: scipproto.Descriptor_Term, - }, - }, gomock.Any()). - Return(nil, "def.go", assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "error loading definition document", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - symInfo := &model.SymbolInformation{ - Symbol: tracingUUIDKey, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "code.uber.internal/devexp/test_management/tracing", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "PipelineUUIDTagKey", - Suffix: scipproto.Descriptor_Term, - }, - }, gomock.Any()). - Return(symInfo, "def.go", nil) - mock.EXPECT(). - LoadDocument("def.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "definition document not found", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - symInfo := &model.SymbolInformation{ - Symbol: tracingUUIDKey, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - GetSymbolInformationFromDescriptors([]model.Descriptor{ - { - Name: "code.uber.internal/devexp/test_management/tracing", - Suffix: scipproto.Descriptor_Namespace, - }, - { - Name: "PipelineUUIDTagKey", - Suffix: scipproto.Descriptor_Term, - }, - }, gomock.Any()). - Return(symInfo, "def.go", nil) - mock.EXPECT(). - LoadDocument("def.go"). - Return(nil, nil) - }, - }, - { - name: "symbol parse error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: "invalid symbol", - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - }, - expectedError: "reached end of symbol while parsing", - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - sourceSymOcc, defSymOcc, err := registry.Definition(tt.sourceURI, tt.pos) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - return - } - - require.NoError(t, err) - - if tt.expectedSource == nil { - assert.Nil(t, sourceSymOcc) - } else { - require.NotNil(t, sourceSymOcc) - assert.Equal(t, tt.expectedSource.Info, sourceSymOcc.Info) - assert.Equal(t, tt.expectedSource.Occurrence, sourceSymOcc.Occurrence) - assert.Equal(t, tt.expectedSource.Location, sourceSymOcc.Location) - } - - if tt.expectedDef == nil { - assert.Nil(t, defSymOcc) - } else { - require.NotNil(t, defSymOcc) - assert.Equal(t, tt.expectedDef.Info, defSymOcc.Info) - assert.Equal(t, tt.expectedDef.Occurrence, defSymOcc.Occurrence) - assert.Equal(t, tt.expectedDef.Location, defSymOcc.Location) - } - }) - } -} - -// locationEqual compares two protocol.Location objects for equality -func locationEqual(a, b protocol.Location) bool { - return a.URI == b.URI && - a.Range.Start.Line == b.Range.Start.Line && - a.Range.Start.Character == b.Range.Start.Character && - a.Range.End.Line == b.Range.End.Line && - a.Range.End.Character == b.Range.End.Character -} - -// containsLocation checks if a location exists in a slice of locations -func containsLocation(locations []protocol.Location, target protocol.Location) bool { - for _, loc := range locations { - if locationEqual(loc, target) { - return true - } - } - return false -} - -// locationsEqual compares two slices of locations without considering order -func locationsEqual(a, b []protocol.Location) bool { - if len(a) != len(b) { - return false - } - for _, loc := range a { - if !containsLocation(b, loc) { - return false - } - } - return true -} - -func TestPartialScipRegistry_References(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - sourceURI uri.URI - pos protocol.Position - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedLocs []protocol.Location - expectedError string - }{ - { - name: "document load error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "document not found", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, nil) - }, - expectedLocs: nil, - }, - { - name: "no occurrence at position", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{}, - }, nil) - }, - expectedLocs: nil, - }, - { - name: "local symbol references", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: "local 1", - Range: []int32{1, 1, 1, 2}, - } - refOcc := &model.Occurrence{ - Symbol: "local 1", - Range: []int32{2, 1, 2, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc, refOcc}, - }, nil) - }, - expectedLocs: []protocol.Location{ - { - URI: uri.File("/workspace/test.go"), - Range: protocol.Range{ - Start: protocol.Position{Line: 1, Character: 1}, - End: protocol.Position{Line: 1, Character: 2}, - }, - }, - { - URI: uri.File("/workspace/test.go"), - Range: protocol.Range{ - Start: protocol.Position{Line: 2, Character: 1}, - End: protocol.Position{Line: 2, Character: 2}, - }, - }, - }, - }, - { - name: "global symbol references", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - - // References in multiple files - refs := map[string][]*model.Occurrence{ - "test.go": { - { - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - }, - }, - "other.go": { - { - Symbol: tracingUUIDKey, - Range: []int32{5, 1, 5, 2}, - }, - }, - } - mock.EXPECT(). - References(tracingUUIDKey). - Return(refs, nil) - }, - expectedLocs: []protocol.Location{ - { - URI: uri.File("/workspace/test.go"), - Range: protocol.Range{ - Start: protocol.Position{Line: 1, Character: 1}, - End: protocol.Position{Line: 1, Character: 2}, - }, - }, - { - URI: uri.File("/workspace/other.go"), - Range: protocol.Range{ - Start: protocol.Position{Line: 5, Character: 1}, - End: protocol.Position{Line: 5, Character: 2}, - }, - }, - }, - }, - { - name: "global symbol references error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - sourceOcc := &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - mock.EXPECT(). - References(tracingUUIDKey). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - locations, err := registry.References(tt.sourceURI, tt.pos) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - return - } - - require.NoError(t, err) - if tt.expectedLocs == nil { - assert.Nil(t, locations) - } else { - require.Equal(t, len(tt.expectedLocs), len(locations)) - assert.True(t, locationsEqual(locations, tt.expectedLocs), - "Locations don't match expected locations (ignoring order)") - } - }) - } -} - -func TestPartialScipRegistry_Hover(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - sourceURI uri.URI - pos protocol.Position - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedDocs string - expectedOcc *model.Occurrence - expectedError string - }{ - { - name: "document load error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "document not found", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, nil) - }, - }, - { - name: "no occurrence at position", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{}, - }, nil) - }, - }, - { - name: "symbol information error", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - occ := &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{occ}, - }, nil) - mock.EXPECT(). - GetSymbolInformation("test"). - Return(nil, "", assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "override documentation", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - occ := &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - OverrideDocumentation: []string{"Override doc line 1", "Override doc line 2"}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{occ}, - }, nil) - mock.EXPECT(). - GetSymbolInformation("test"). - Return(&model.SymbolInformation{ - Symbol: "test", - Documentation: []string{"Symbol doc line 1", "Symbol doc line 2"}, - }, "", nil) - }, - expectedDocs: "Override doc line 1\nOverride doc line 2", - expectedOcc: &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - OverrideDocumentation: []string{"Override doc line 1", "Override doc line 2"}, - }, - }, - { - name: "symbol documentation", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - occ := &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{occ}, - }, nil) - mock.EXPECT(). - GetSymbolInformation("test"). - Return(&model.SymbolInformation{ - Symbol: "test", - Documentation: []string{"Symbol doc line 1", "Symbol doc line 2"}, - }, "", nil) - }, - expectedDocs: "Symbol doc line 1\nSymbol doc line 2", - expectedOcc: &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - }, - }, - { - name: "signature documentation", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - occ := &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{occ}, - }, nil) - mock.EXPECT(). - GetSymbolInformation("test"). - Return(&model.SymbolInformation{ - Symbol: "test", - SignatureDocumentation: &model.Document{ - Text: "Signature documentation", - Language: "go", - }, - }, "", nil) - }, - expectedDocs: "Signature documentation", - expectedOcc: &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - }, - }, - { - name: "no documentation", - sourceURI: uri.File("/workspace/test.go"), - pos: protocol.Position{Line: 1, Character: 1}, - setupMock: func(mock *partialloadermock.MockPartialIndex) { - occ := &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - } - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{occ}, - }, nil) - mock.EXPECT(). - GetSymbolInformation("test"). - Return(&model.SymbolInformation{ - Symbol: "test", - }, "", nil) - }, - expectedDocs: "", - expectedOcc: &model.Occurrence{ - Symbol: "test", - Range: []int32{1, 1, 1, 2}, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - docs, occ, err := registry.Hover(tt.sourceURI, tt.pos) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - return - } - - require.NoError(t, err) - assert.Equal(t, tt.expectedDocs, docs) - - if tt.expectedOcc == nil { - assert.Nil(t, occ) - } else { - require.NotNil(t, occ) - assert.Equal(t, tt.expectedOcc.Symbol, occ.Symbol) - assert.Equal(t, tt.expectedOcc.Range, occ.Range) - assert.Equal(t, tt.expectedOcc.OverrideDocumentation, occ.OverrideDocumentation) - } - }) - } -} - -func TestPartialScipRegistry_DocumentSymbols(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - tests := []struct { - name string - sourceURI uri.URI - setupMock func(mock *partialloadermock.MockPartialIndex) - expectedSymbols []*model.SymbolOccurrence - expectedError string - }{ - { - name: "document load error", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, assert.AnError) - }, - expectedError: assert.AnError.Error(), - }, - { - name: "document not found", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(nil, nil) - }, - expectedSymbols: nil, - }, - { - name: "empty document", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{}, - SymbolMap: map[string]*model.SymbolInformation{}, - }, nil) - }, - expectedSymbols: []*model.SymbolOccurrence{}, - }, - { - name: "local symbols only", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{ - { - Symbol: "local 1", - Range: []int32{1, 1, 1, 2}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - }, - SymbolMap: map[string]*model.SymbolInformation{ - "local 1": { - Symbol: "local 1", - DisplayName: "LocalVar", - }, - }, - }, nil) - }, - expectedSymbols: []*model.SymbolOccurrence{}, - }, - { - name: "global symbols with definitions", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{ - { - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - { - Symbol: "global2", - Range: []int32{2, 1, 2, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - { - Symbol: "global3", - Range: []int32{3, 1, 3, 10}, - // Not a definition - }, - }, - SymbolMap: map[string]*model.SymbolInformation{ - tracingUUIDKey: { - Symbol: tracingUUIDKey, - DisplayName: "TracingUUID", - }, - "global2": { - Symbol: "global2", - DisplayName: "Global2", - }, - "global3": { - Symbol: "global3", - DisplayName: "Global3", - }, - }, - }, nil) - }, - expectedSymbols: []*model.SymbolOccurrence{ - { - Info: &model.SymbolInformation{ - Symbol: tracingUUIDKey, - DisplayName: "TracingUUID", - }, - Occurrence: &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - Location: uri.File("/workspace/test.go"), - }, - { - Info: &model.SymbolInformation{ - Symbol: "global2", - DisplayName: "Global2", - }, - Occurrence: &model.Occurrence{ - Symbol: "global2", - Range: []int32{2, 1, 2, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - Location: uri.File("/workspace/test.go"), - }, - }, - }, - { - name: "global symbols with empty display name", - sourceURI: uri.File("/workspace/test.go"), - setupMock: func(mock *partialloadermock.MockPartialIndex) { - mock.EXPECT(). - LoadDocument("test.go"). - Return(&model.Document{ - Occurrences: []*model.Occurrence{ - { - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - }, - SymbolMap: map[string]*model.SymbolInformation{ - tracingUUIDKey: { - Symbol: tracingUUIDKey, - // DisplayName is empty, should be parsed from symbol - }, - }, - }, nil) - }, - expectedSymbols: []*model.SymbolOccurrence{ - { - Info: &model.SymbolInformation{ - Symbol: tracingUUIDKey, - DisplayName: "PipelineUUIDTagKey", - }, - Occurrence: &model.Occurrence{ - Symbol: tracingUUIDKey, - Range: []int32{1, 1, 1, 10}, - SymbolRoles: int32(scipproto.SymbolRole_Definition), - }, - Location: uri.File("/workspace/test.go"), - }, - }, - }, - } - - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - tt.setupMock(mockIndex) - - symbols, err := registry.DocumentSymbols(tt.sourceURI) - - if tt.expectedError != "" { - require.Error(t, err) - assert.Contains(t, err.Error(), tt.expectedError) - return - } - - require.NoError(t, err) - if tt.expectedSymbols == nil { - assert.Nil(t, symbols) - } else { - assert.ElementsMatch(t, tt.expectedSymbols, symbols) - } - }) - } -} - -func TestPartialScipRegistry_Implementation_FastPath(t *testing.T) { - ctrl := gomock.NewController(t) - mockIndex := partialloadermock.NewMockPartialIndex(ctrl) - logger := zaptest.NewLogger(t).Sugar() - - registry := &partialScipRegistry{ - WorkspaceRoot: "/workspace", - Index: mockIndex, - logger: logger, - } - - sourceURI := uri.File("/workspace/test.go") - pos := protocol.Position{Line: 1, Character: 1} - - sourceOcc := &model.Occurrence{Symbol: tracingUUIDKey, Range: []int32{1, 1, 1, 2}} - mockIndex.EXPECT().LoadDocument("test.go").Return(&model.Document{ - Occurrences: []*model.Occurrence{sourceOcc}, - }, nil) - - mockIndex.EXPECT().Implementations(tracingUUIDKey).Return([]string{ - "scip-go gomod example/pkg v1.0.0 `example/pkg`/Foo#Bar.", - }, nil) - - mockIndex.EXPECT().GetSymbolInformationFromDescriptors(gomock.Any(), gomock.Any()).Return(&model.SymbolInformation{Symbol: "impl#sym"}, "impl.go", nil) - mockIndex.EXPECT().LoadDocument("impl.go").Return(&model.Document{ - Occurrences: []*model.Occurrence{ - {Symbol: "impl#sym", SymbolRoles: int32(scipproto.SymbolRole_Definition), Range: []int32{10, 1, 10, 5}}, - }, - }, nil) - - locs, err := registry.Implementation(sourceURI, pos) - require.NoError(t, err) - require.Equal(t, 1, len(locs)) - assert.Equal(t, uri.File("/workspace/impl.go"), locs[0].URI) - assert.Equal(t, protocol.Position{Line: 10, Character: 1}, locs[0].Range.Start) - assert.Equal(t, protocol.Position{Line: 10, Character: 5}, locs[0].Range.End) -} diff --git a/src/ulsp/controller/scip/scip.go b/src/ulsp/controller/scip/scip.go index 9843155..6c9d75d 100644 --- a/src/ulsp/controller/scip/scip.go +++ b/src/ulsp/controller/scip/scip.go @@ -118,7 +118,7 @@ func New(p Params) (Controller, error) { indexNotifier: NewIndexNotifier(notifier.NewNotificationManager(notificationManagerParams)), newScipRegistry: func(workspaceRoot, indexFolder string) registry.Registry { p.Logger.Infof("Creating new SCIP registry for %q, index folder %q", workspaceRoot, indexFolder) - return NewPartialScipRegistry(workspaceRoot, indexFolder, p.Logger.Named("fast-loader")) + return registry.NewPartialScipRegistry(workspaceRoot, indexFolder, p.Logger.Named("fast-loader")) }, }, nil }