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  }