all repos

clerk @ b36147319e95509014992fd3832247e82733d6c6

missing tooling for ledger/hledger

clerk/internal/lsp/textdocument_completion_test.go (view raw)

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
tests: consistent golden.Read placement, 1 month ago
1
// TODO:
2
package lsp
3
4
import (
5
	"fmt"
6
	"strings"
7
	"testing"
8
	"time"
9
10
	"go.lsp.dev/protocol"
11
	"go.lsp.dev/uri"
12
13
	"olexsmir.xyz/clerk/internal/lsp/lsputil"
14
	"olexsmir.xyz/clerk/internal/testutil/golden"
15
	"olexsmir.xyz/clerk/journal"
16
)
17
18
func TestDetectCompletion_NoJournal(t *testing.T) {
19
	// detection must not depend on a parse
20
	i := strings.Index("    no^te foo\n", "^")
21
	content := "    note foo\n"
22
	ctx, _ := detectCompletionCtx(content, i)
23
	if ctx != cmplAccount {
24
		t.Errorf("ctx = %v, want account", ctx)
25
	}
26
}
27
28
func TestGolden_Completion(t *testing.T) {
29
	for _, tt := range []string{"completion-contexts", "completion-journal", "completion-no-transactions"} {
30
		t.Run(tt, func(t *testing.T) {
31
			ar := golden.Read(t, tt)
32
			h := newTxtarHarness(t, ar)
33
34
			var b strings.Builder
35
			for i, c := range h.cursors {
36
				tdp := h.textDocumentPosition(i)
37
				res, err := h.srv.Completion(t.Context(), &protocol.CompletionParams{
38
					TextDocumentPositionParams: tdp,
39
				})
40
				if err != nil {
41
					t.Fatal(err)
42
				}
43
				ctx, start := detectCompletionCtx(h.content, c)
44
				fmt.Fprintf(&b, "%d:%d %s %q\n", tdp.Position.Line, tdp.Position.Character, ctx, h.content[start:c])
45
				list, ok := res.(*protocol.CompletionList)
46
				if !ok {
47
					t.Fatalf("Completion returned %T, want *protocol.CompletionList", res)
48
				}
49
				for _, item := range list.Items {
50
					fmt.Fprintf(&b, "  %s\n", item.Label)
51
				}
52
			}
53
			golden.Assert(t, ar, b.String())
54
		})
55
	}
56
}
57
58
func (c cmplCtx) String() string {
59
	switch c {
60
	case cmplNone:
61
		return "none"
62
	case cmplAccount:
63
		return "account"
64
	case cmplPayee:
65
		return "payee"
66
	case cmplCommodity:
67
		return "commodity"
68
	case cmplTagName:
69
		return "tag"
70
	case cmplTagValue:
71
		return "tag-value"
72
	case cmplDirective:
73
		return "directive"
74
	default:
75
		return "?"
76
	}
77
}
78
79
func BenchmarkCompletion(b *testing.B) {
80
	path := "../../journal/testdata/journals/actual-1ktxns-100accts.journal"
81
	rj, err := journal.NewLoader().Resolve(path)
82
	if err != nil {
83
		b.Fatal(err)
84
	}
85
	content := string(rj.Occurrences[0].Src)
86
87
	srv := NewServer("test")
88
	srv.server.openDoc(uri.URI("file:///test.journal"), content, 1, "journal")
89
	srv.server.analysisFor(uri.URI("file:///test.journal")) // warm the per-doc cache
90
91
	for tname, tt := range map[string]int{
92
		"1k txns, account":     strings.Index(content, "\n  1:2:3 ") + len("\n  ") + 2,
93
		"1k txns, empty payee": strings.Index(content, "transaction 1") + len("transaction "),
94
		"1k txns, commodity":   strings.Index(content, "2 B @@") + len("2 B"),
95
	} {
96
		b.Run(tname, func(b *testing.B) {
97
			line, col := lsputil.LineCol(content, tt)
98
			params := &protocol.CompletionParams{
99
				TextDocumentPositionParams: protocol.TextDocumentPositionParams{
100
					TextDocument: protocol.TextDocumentIdentifier{URI: uri.URI("file:///test.journal")},
101
					Position:     protocol.Position{Line: uint32(line), Character: uint32(col)},
102
				},
103
			}
104
105
			// warm up
106
			if _, err := srv.server.Completion(b.Context(), params); err != nil {
107
				b.Fatal(err)
108
			}
109
			b.ReportAllocs()
110
			b.ResetTimer()
111
			for b.Loop() {
112
				if _, err := srv.server.Completion(b.Context(), params); err != nil {
113
					b.Fatal(err)
114
				}
115
			}
116
			// guard: line-local lexing must stay far below the old whole-file
117
			// relex (~3ms on this file); the measured target is sub-ms
118
			if avg := b.Elapsed() / time.Duration(b.N); avg > 2*time.Millisecond {
119
				b.Fatalf("completion %v/op: whole-file relex regression", avg)
120
			}
121
		})
122
	}
123
}