all repos

clerk @ 122b3849cfb7f6cd41be7fcceaeced24df42dae9

missing tooling for ledger/hledger

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

Oleksandr Smirnov Oleksandr Smirnov
olexsmir@gmail.com
tests: consistent golden.Read placement, 1 month ago
1
package lsp
2
3
import (
4
	"context"
5
	"fmt"
6
	"path/filepath"
7
	"strings"
8
	"testing"
9
	"time"
10
11
	"go.lsp.dev/protocol"
12
	"go.lsp.dev/uri"
13
14
	"olexsmir.xyz/clerk/internal/lsp/lsputil"
15
	"olexsmir.xyz/clerk/internal/testutil/golden"
16
)
17
18
func TestServer_References_DocumentNotFound(t *testing.T) {
19
	srv := NewServer("test")
20
	res, err := srv.server.References(context.Background(), &protocol.ReferenceParams{
21
		TextDocumentPositionParams: protocol.TextDocumentPositionParams{
22
			TextDocument: protocol.TextDocumentIdentifier{URI: uri.URI("file:///nonexistent.journal")},
23
			Position:     protocol.Position{Line: 0, Character: 0},
24
		},
25
	})
26
	if err != nil {
27
		t.Fatal(err)
28
	}
29
	if res != nil {
30
		t.Errorf("got %v, want nil", res)
31
	}
32
}
33
34
func TestGolden_References(t *testing.T) {
35
	for _, tt := range []string{"references-journal", "references-include"} {
36
		t.Run(tt, func(t *testing.T) {
37
			ar := golden.Read(t, tt)
38
			h := newTxtarHarness(t, ar)
39
40
			var b strings.Builder
41
			for _, incl := range []bool{false, true} {
42
				fmt.Fprintf(&b, "includeDeclaration:%v\n", incl)
43
				for i := range h.cursors {
44
					txtDocPos := h.textDocumentPosition(i)
45
					res, err := h.srv.References(t.Context(), &protocol.ReferenceParams{
46
						Context:                    protocol.ReferenceContext{IncludeDeclaration: incl},
47
						TextDocumentPositionParams: txtDocPos,
48
					})
49
					if err != nil {
50
						t.Fatal(err)
51
					}
52
					if len(res) == 0 {
53
						fmt.Fprintf(&b, "%d:%d <none>\n", txtDocPos.Position.Line, txtDocPos.Position.Character)
54
						continue
55
					}
56
					for _, loc := range res {
57
						r := loc.Range
58
						fmt.Fprintf(&b, "%d:%d %s %d:%d-%d:%d\n", txtDocPos.Position.Line, txtDocPos.Position.Character,
59
							filepath.Base(loc.URI.Path()),
60
							r.Start.Line, r.Start.Character, r.End.Line, r.End.Character)
61
					}
62
				}
63
			}
64
			golden.Assert(t, ar, b.String())
65
		})
66
	}
67
}
68
69
func BenchmarkReferences(b *testing.B) {
70
	content := openJournal(b, "../../journal/testdata/journals/actual-1ktxns-100accts.journal")
71
72
	srv := NewServer("test")
73
	u := uri.URI("file:///test.journal")
74
	srv.server.openDoc(u, content, 1, "journal")
75
	srv.server.analysisFor(u) // warm per-doc cache
76
77
	for tname, tt := range map[string]int{
78
		"1k txns, account":   strings.Index(content, "\n  1:2:3 ") + len("\n  ") + 2,
79
		"1k txns, payee":     strings.Index(content, "transaction 1") + len("transaction "),
80
		"1k txns, commodity": strings.Index(content, "2 B @@") + len("2 B"),
81
		"late tx, payee":     strings.Index(content, "transaction 1000") + len("transaction "),
82
	} {
83
		b.Run(tname, func(b *testing.B) {
84
			line, col := lsputil.LineCol(content, tt)
85
			params := &protocol.ReferenceParams{
86
				Context: protocol.ReferenceContext{IncludeDeclaration: true},
87
				TextDocumentPositionParams: protocol.TextDocumentPositionParams{
88
					TextDocument: protocol.TextDocumentIdentifier{URI: u},
89
					Position:     protocol.Position{Line: uint32(line), Character: uint32(col)},
90
				},
91
			}
92
93
			// warm up: first request resolves the symbol lazily; assert it found references
94
			res, err := srv.server.References(b.Context(), params)
95
			if err != nil {
96
				b.Fatal(err)
97
			}
98
			if len(res) == 0 {
99
				b.Fatalf("%s: no references", tname)
100
			}
101
102
			b.ReportAllocs()
103
			b.ResetTimer()
104
			for b.Loop() {
105
				if _, err := srv.server.References(b.Context(), params); err != nil {
106
					b.Fatal(err)
107
				}
108
			}
109
110
			// guard: a whole-file re-parse per request (~13ms) would blow past
111
			// this and must be caught
112
			if avg := b.Elapsed() / time.Duration(b.N); avg > 5*time.Millisecond {
113
				b.Fatalf("references %v/op: reparse regression", avg)
114
			}
115
		})
116
	}
117
}