golang.org/x/tools/gopls@v0.15.3/internal/template/completion_test.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package template 6 7 import ( 8 "log" 9 "sort" 10 "strings" 11 "testing" 12 13 "golang.org/x/tools/gopls/internal/protocol" 14 ) 15 16 func init() { 17 log.SetFlags(log.Lshortfile) 18 } 19 20 type tparse struct { 21 marked string // ^ shows where to ask for completions. (The user just typed the following character.) 22 wanted []string // expected completions 23 } 24 25 // Test completions in templates that parse enough (if completion needs symbols) 26 // Seen characters up to the ^ 27 func TestParsed(t *testing.T) { 28 var tests = []tparse{ 29 {"{{x}}{{12. xx^", nil}, // https://github.com/golang/go/issues/50430 30 {`<table class="chroma" data-new-comment-url="{{if $.PageIsPullFiles}}{{$.Issue.HTMLURL}}/files/reviews/new_comment{{else}}{{$.CommitHTML}}/new_comment^{{end}}">`, nil}, 31 {"{{i^f}}", []string{"index", "if"}}, 32 {"{{if .}}{{e^ {{end}}", []string{"eq", "end}}", "else", "end"}}, 33 {"{{foo}}{{f^", []string{"foo"}}, 34 {"{{$^}}", []string{"$"}}, 35 {"{{$x:=4}}{{$^", []string{"$x"}}, 36 {"{{$x:=4}}{{$ ^ ", []string{}}, 37 {"{{len .Modified}}{{.^Mo", []string{"Modified"}}, 38 {"{{len .Modified}}{{.mf^", []string{"Modified"}}, 39 {"{{$^ }}", []string{"$"}}, 40 {"{{$a =3}}{{$^", []string{"$a"}}, 41 // .two is not good here: fix someday 42 {`{{.Modified}}{{.^{{if $.one.two}}xxx{{end}}`, []string{"Modified", "one", "two"}}, 43 {`{{.Modified}}{{.o^{{if $.one.two}}xxx{{end}}`, []string{"one"}}, 44 {"{{.Modiifed}}{{.one.t^{{if $.one.two}}xxx{{end}}", []string{"two"}}, 45 {`{{block "foo" .}}{{i^`, []string{"index", "if"}}, 46 {"{{in^{{Internal}}", []string{"index", "Internal", "if"}}, 47 // simple number has no completions 48 {"{{4^e", []string{}}, 49 // simple string has no completions 50 {"{{`e^", []string{}}, 51 {"{{`No i^", []string{}}, // example of why go/scanner is used 52 {"{{xavier}}{{12. x^", []string{"xavier"}}, 53 } 54 for _, tx := range tests { 55 c := testCompleter(t, tx) 56 var v []string 57 if c != nil { 58 ans, _ := c.complete() 59 for _, a := range ans.Items { 60 v = append(v, a.Label) 61 } 62 } 63 if len(v) != len(tx.wanted) { 64 t.Errorf("%q: got %q, wanted %q %d,%d", tx.marked, v, tx.wanted, len(v), len(tx.wanted)) 65 continue 66 } 67 sort.Strings(tx.wanted) 68 sort.Strings(v) 69 for i := 0; i < len(v); i++ { 70 if tx.wanted[i] != v[i] { 71 t.Errorf("%q at %d: got %v, wanted %v", tx.marked, i, v, tx.wanted) 72 break 73 } 74 } 75 } 76 } 77 78 func testCompleter(t *testing.T, tx tparse) *completer { 79 t.Helper() 80 // seen chars up to ^ 81 col := strings.Index(tx.marked, "^") 82 buf := strings.Replace(tx.marked, "^", "", 1) 83 p := parseBuffer([]byte(buf)) 84 pos := protocol.Position{Line: 0, Character: uint32(col)} 85 if p.ParseErr != nil { 86 log.Printf("%q: %v", tx.marked, p.ParseErr) 87 } 88 offset := inTemplate(p, pos) 89 if offset == -1 { 90 return nil 91 } 92 syms := make(map[string]symbol) 93 filterSyms(syms, p.symbols) 94 c := &completer{ 95 p: p, 96 pos: protocol.Position{Line: 0, Character: uint32(col)}, 97 offset: offset + len(Left), 98 ctx: protocol.CompletionContext{TriggerKind: protocol.Invoked}, 99 syms: syms, 100 } 101 return c 102 }