package completion import ( "context" "errors" "testing" ) type fakeLSPClient struct { openCalls []openCall changeCalls []changeCall completionCalls []completionCall completionResp Response openErr error changeErr error completionErr error } type openCall struct { uri string text string version int } type changeCall struct { uri string text string version int } type completionCall struct { uri string line int character int } func (f *fakeLSPClient) DidOpen(_ context.Context, uri, text string, version int) error { f.openCalls = append(f.openCalls, openCall{uri: uri, text: text, version: version}) return f.openErr } func (f *fakeLSPClient) DidChange(_ context.Context, uri, text string, version int) error { f.changeCalls = append(f.changeCalls, changeCall{uri: uri, text: text, version: version}) return f.changeErr } func (f *fakeLSPClient) Completion(_ context.Context, uri string, line, character int) (Response, error) { f.completionCalls = append(f.completionCalls, completionCall{uri: uri, line: line, character: character}) if f.completionErr != nil { return Response{}, f.completionErr } return f.completionResp, nil } func TestServiceCompleteFirstRequestSendsDidOpen(t *testing.T) { fake := &fakeLSPClient{ completionResp: Response{Items: []Item{{Label: "Println"}}, IsIncomplete: true}, } svc := NewService(fake) resp, err := svc.Complete(context.Background(), Request{ URI: "file:///main.go", Text: "package main\nfunc main() { fmt.Pr }", Line: 1, Character: 23, }) if err != nil { t.Fatalf("Complete() error = %v", err) } if len(fake.openCalls) != 1 { t.Fatalf("expected 1 didOpen call, got %d", len(fake.openCalls)) } if fake.openCalls[0].version != 1 { t.Fatalf("expected didOpen version=1, got %d", fake.openCalls[0].version) } if len(fake.changeCalls) != 0 { t.Fatalf("expected 0 didChange calls, got %d", len(fake.changeCalls)) } if len(fake.completionCalls) != 1 { t.Fatalf("expected 1 completion call, got %d", len(fake.completionCalls)) } if !resp.IsIncomplete || len(resp.Items) != 1 || resp.Items[0].Label != "Println" { t.Fatalf("unexpected response: %+v", resp) } } func TestServiceCompleteSecondRequestUsesDidChange(t *testing.T) { fake := &fakeLSPClient{} svc := NewService(fake) _, err := svc.Complete(context.Background(), Request{ URI: "file:///main.go", Text: "package main\nfunc main() {}", Line: 1, Character: 12, }) if err != nil { t.Fatalf("first Complete() error = %v", err) } _, err = svc.Complete(context.Background(), Request{ URI: "file:///main.go", Text: "package main\nfunc main() { fmt.Pr }", Line: 1, Character: 23, }) if err != nil { t.Fatalf("second Complete() error = %v", err) } if len(fake.openCalls) != 1 { t.Fatalf("expected 1 didOpen call, got %d", len(fake.openCalls)) } if len(fake.changeCalls) != 1 { t.Fatalf("expected 1 didChange call, got %d", len(fake.changeCalls)) } if fake.changeCalls[0].version != 2 { t.Fatalf("expected didChange version=2, got %d", fake.changeCalls[0].version) } } func TestServiceCompleteValidatesRequest(t *testing.T) { svc := NewService(&fakeLSPClient{}) _, err := svc.Complete(context.Background(), Request{URI: "", Text: "", Line: -1, Character: 0}) if !errors.Is(err, ErrInvalidRequest) { t.Fatalf("expected ErrInvalidRequest, got %v", err) } } func TestServiceCompleteReturnsClientError(t *testing.T) { fake := &fakeLSPClient{openErr: errors.New("open failed")} svc := NewService(fake) _, err := svc.Complete(context.Background(), Request{ URI: "file:///main.go", Text: "package main", Line: 0, Character: 0, }) if err == nil { t.Fatal("expected error, got nil") } }